一. 简单工厂模式
又称为静态工厂方法(Static Factory Method)模式,它属于创建型模式,专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
1.1 场景
- 工厂类负责创建的对象比较少,不会造成业务逻辑太复杂
- 客户端只知道传入工厂类的参数,对如何创建类并不关心
1.2 优点
- 实现了对责任的分割,工厂类负责创建产品对象,客户端负责“消费”即可,且不需要记住产品类的类名
1.3 缺点
- 工厂类负责所有产品的创建,一旦不能工作将影响整个系统
- 违反开闭原则,一旦需要添加产品就需要修改工厂类的实现逻辑,产品太多可能造成工厂类逻辑复杂
- 简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构。
1. 创建teacher接口
/**
* teacher接口,定义方法
*
* @author dkangle
*/
public interface Teacher {
void teach();
}
2. 实现teacher接口
/**
* 数学老师
*
* @author dkangel
*/
public class MathTeacher implements Teacher {
@Override
public void teach() {
System.out.println("I teach math.");
}
}
/**
* 英语老师
*
* @author dkangel
*/
public class EnglishTeacher implements Teacher {
@Override
public void teach() {
System.out.println("I teach english.");
}
}
3. 创建teacher工厂类,并创建静态方法获取teacher实例
/**
* teacher工厂类
* <p>
* 定义一个工厂类专门实例化teacher实例,这些实例具有相同的父类
*
* @author dkangel
*/
public static class TeacherFactory {
public Teacher getTeacher(String type) {
if ("math".equals(type)) {
return new MathTeacher();
} else if ("english".equals(type)) {
return new EnglishTeacher();
}
return null;
}
}
4. 使用
/**
* 简单工厂使用类
*
* @author dkangel
*/
public class Main {
public static void main(String[] args) {
// 数学老师
Teacher teacher = TeacherFactory.getTeacher("math");
teacher.teach();
// 英语老师
teacher = TeacherFactory.getTeacher("english");
teacher.teach();
}
}
二. 工厂方法模式
又称工厂模式、多态工厂模式和虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。
2.1 场景
- 当一个类不知道它所需要的对象的类时
- 当一个类希望通过其子类来指定创建对象时
2.2 优点
- 符合开闭原则,新增产品时,只需要增加具体的产品类和工厂子类即可
- 符合单一职责原则,一个工厂子类只负责创建对应的产品
- 不使用静态工厂方法,可以形成基于继承的等级结构
2.3 缺点
- 添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度
- 一个具体工厂只能创建一种具体产品
1. 创建抽象工厂类
/**
* teacher接口
*
* @author dkangel
*/
public interface Teacher {
/**
* 教学
*/
void teach();
}
2. 创建抽象teacher类
/**
* teacher类
*
* @author dkangel
*/
public abstract class Teacher {
/**
* 教学
*/
public abstract void teach();
}
3. 创建具体的teacher类
/**
* math teacher类
*
* @author dkangel
*/
public class MathTeacher implements Teacher {
@Override
public void teach() {
System.out.println("I am math teacher.");
}
}
4. 创建具体工厂类
/**
* 具体工厂类 math teacher factory
*
* @author dkangel
*/
public class MathFactory extends Factory {
@Override
public Teacher getTeacher() {
return new MathTeacher();
}
}
5. 使用
/**
* 工厂方法使用类
*
* @author dkangel
*/
public class Main {
public static void main(String[] args) {
// 数学老师
AbstractFactory factory = new MathFactory();
Teacher teacher = factory.getTeacher();
// 英语老师
factory = new EnglishFactory();
teacher = factory.getTeacher();
}
}
三. 抽象工厂模式
提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。围绕超级工厂创建其他工厂
3.1 场景
- 一个系统不要求依赖产品类实例如何被创建、组合和表达的表达,这点也是所有工厂模式应用的前提
- 这个系统有多个系列产品,而系统中只消费其中某一系列产品
- 系统要求提供一个产品类的库,所有产品以同样的接口出现,客户端不需要依赖具体实现
3.2 优点
- 降低耦合
抽象工厂模式将具体产品的创建延迟到具体工厂的子类中,这样将对象的创建封装起来,可以减少客户端与具体产品类之间的依赖,从而使系统耦合度低,这样更有利于后期的维护和扩展; - 更符合开-闭原则
新增一种产品类时,只需要增加相应的具体产品类和相应的工厂子类即可 - 符合单一职责原则
每个具体工厂类只负责创建对应的产品 - 不使用静态工厂方法,可以形成基于继承的等级结构。
3.3 缺点
- 抽象工厂模式很难支持新种类产品的变化。
这是因为抽象工厂接口中已经确定了可以被创建的产品集合,如果需要添加新产品,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类的以及所有子类的改变,这样也就违背了“开发——封闭”原则
1. 创建电脑接口
/**
* 电脑接口
*
* @author dkangel
*/
public interface Computer {
/**
* 写代码
*/
void code();
}
2. 创建电脑实现类
public class HuaweiComputer implements Computer {
@Override
public void code() {
System.out.println("Huawei Computer code.");
}
}
public class AppleComputer implements Computer {
@Override
public void code() {
System.out.println("Apple Computer code.");
}
}
3. 创建手机接口
/**
* 手机接口
*
* @author dkangel
*/
public interface Phone {
/**
* 打电话
*/
void call();
}
4. 创建手机实现类
public class HuaweiPhone implements Phone {
@Override
public void call() {
System.out.println("Huawei Phone call.");
}
}
public class ApplePhone implements Phone {
@Override
public void call() {
System.out.println("Apple Phone call.");
}
}
5. 创建抽象工厂类
/**
* 工厂类
*
* @author dkangel
*/
public abstract class AbstractFactory {
/**
* 生产手机
*
* @return Phone
*/
public abstract Phone manufacturePhone(String company);
/**
* 生产电脑
*
* @return Computer
*/
public abstract Computer manufactureComputer(String company);
}
6. 创建电脑、手机工厂类
/**
* Computer工厂类
*
* @author dkangel
*/
public class ComputerFactory extends AbstractFactory {
@Override
public Phone manufacturePhone(String company) {
return null;
}
@Override
public Computer manufactureComputer(String company) {
if ("Huawei".equalsIgnoreCase(company)) {
return new HuaweiComputer();
} else if ("Apple".equalsIgnoreCase(company)) {
return new AppleComputer();
}
return null;
}
}
/**
* Phone工厂类
*
* @author dkangel
*/
public class PhoneFactory extends AbstractFactory {
@Override
public Phone manufacturePhone(String company) {
if ("Huawei".equalsIgnoreCase(company)) {
return new HuaweiPhone();
} else if ("Apple".equalsIgnoreCase(company)) {
return new ApplePhone();
}
return null;
}
@Override
public Computer manufactureComputer(String company) {
return null;
}
}
7. 创建超级工厂类
/**
* 超级工厂类,用于创建其具体的工厂类
*
* @author dkangel
*/
public class FactoryProducer {
/**
* 根据type获取具体的工厂
*
* @param type 工厂类型
* @return AbstractFactory
*/
public static AbstractFactory getFactory(String type) {
if ("Phone".equalsIgnoreCase(type)) {
return new PhoneFactory();
} else if ("Computer".equalsIgnoreCase(type)) {
return new ComputerFactory();
}
return null;
}
}
8. 使用
/**
* 抽象工厂使用类
*
* @author dkangel
*/
public class Main {
public static void main(String[] args) {
// 获取Phone工厂
AbstractFactory phoneFactory = FactoryProducer.getFactory("phone");
// 获取Huawei手机
Phone phone = phoneFactory.manufacturePhone("Huawei");
phone.call();
// 获取Apple手机
phone = phoneFactory.manufacturePhone("Apple");
phone.call();
AbstractFactory computerFactory = FactoryProducer.getFactory("computer");
// 获取Huawei电脑
Computer computer = computerFactory.manufactureComputer("Huawei");
computer.code();
// 获取Apple电脑
computer = computerFactory.manufactureComputer("Apple");
computer.code();
}
}