目录
本文脑图
工厂模式简单来说就是提供一个创建对象的工厂,属于创建型模式,工厂模式又可以分为三种,分别是简单工厂模式(Simple Factory Pattern)、工厂方法模式(Factory Method Pattern)、抽象工厂模式(Abstract Factory)。
传送门:代码实验02:设计模式-单例模式
简单工厂模式
- 简单工厂的定义
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
在现实生活中就好比一个汽车厂商,只要你告诉厂商你要的车是什么颜色的,几个座位,多少排量等等参数,那么汽车厂商就可以给你定制出一辆符合你需求的汽车,厂商具备了生产不同汽车的能力。
- 简单工厂包含的角色
- Factory:工厂角色负责实现创建所有实例的内部逻辑
- Product:抽象产品角色抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口
- ConcreteProduct:具体产品角色
具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
简单工厂模式类图:
public interface Product {
void use();
}
public class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("使用A产品");
}
}
public class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println("使用B产品");
}
}
public class SimpleFactory {
public static Product createProduct(String arg) {
if ("A".equals(arg)) {
return new ConcreteProductA();
} else if("B".equals(arg)) {
return new ConcreteProductB();
} else {
return null;
}
}
public static void main(String[] args) {
Product product = createProduct("A");
System.out.println(product);
}
}
从代码可以看出简单工厂有以下的特点:
- 将对象的创建和对象本身的处理业务分离,这样可以降低耦合度,可以两者修改起来都相对容易。
- 在调用工厂类方法时,由于是静态方法使得调用简单,直接通过类名调用传入正确的参数即可。实际开发中可以将参数配置在数据库或缓存中,只需要修改数据库或缓存即可得到不同的对象,而不需要修改代码,但如果新增产品时则需要修改工厂类的逻辑代码,这一点不符合"开闭"原则。
- 简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。
- 简单工厂的优点
降低耦合度,对客户端屏蔽了对象的创建细节,使用简单,新增产品时,客户端无需修改代码。
- 简单工厂的缺点
工厂类包含所有产品对象的创建逻辑,一旦出现异常,整个系统都会受到影响,同时当新增产品时需要修改逻辑代码,违背了“开-闭”原则。
工厂方法模式
工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责哪一个产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。
- 工厂方法的定义
定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类。
工厂方法模式(Factory Method Pattern)又叫虚拟构造函数(VirtualConstructor)模式或者多态性工厂(Polymorphic Factory)模式。工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建性工作推迟到子类中。
- 工厂方法包含的角色
- Product:抽象产品
- ConcreteProduct:具体产品
- Factory:抽象工厂
- ConcreteFactory:具体工厂
// 抽象产品
public interface Product {
void use();
}
// 具体产品
public class ConcreteProduct implements Product {
@Override
public void use() {
System.out.println("具体产品");
}
}
// 抽象工厂
public interface AbstractFactory {
/**
* 工厂方法
**/
<T extends Product> T factory(Class<T> c);
}
// 具体工厂
public class ConcreteFactory implements AbstractFactory {
@Override
public <T extends Product> T factory(Class<T> c) {
T product = null;
try {
product = (T) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return product;
}
// 测试方法
public static void main(String[] args) {
ConcreteFactory concreteFactory = new ConcreteFactory();
ConcreteProduct product = concreteFactory.factory(ConcreteProduct.class);
System.out.println(product);
}
}
- 工厂方法的优点
1.良好的封装性,代码结构清晰。一个对象创建是有条件约束的,如果一个调用者需要一个具体的产品对象,只要知道这个产品的类名或约束字符串即可,不用知道创建对象的过程如何,降低了模块间的耦合。
2.优秀的可扩展性。在增加产品类的情况下,只要适当地修改具体的工厂类或扩展一个工厂类,就可以适应变化。
3.屏蔽产品类。产品类的实现如何变化,调用者都不需要关心,而只需要关心产品的接口,只要接口保持不变,系统的上层模块就不需要发生变化。因为产品的实例化是由工厂类负责的,具体生产何种产品对象是由不同的工厂类决定的。
4.工厂方法模式是典型的解耦框架。高层模块只需要知道产品的抽象类,其他的实现类都不用关心。工厂方法模式符合迪米特法则,也符合依赖倒置原则,只依赖产品类的抽象;另外还符合里氏替换原则,可以使用产品子类替换产品父类。
- 工厂方法的使用场景
- 工厂方法模式的本质是new一个对象的替代品,因此只要是涉及到生成对象的地方都可以使用。
- 需要灵活的、可扩展的框架时,可以考虑采用工厂方法模式。
- 工厂方法模式可以用在异构项目中,例如,通过WebService与一个非Java的项目交互。
- 工厂方法模式可以使用在测试驱动开发的框架下。例如,测试一个类 A,就需要将与类A关联的类B也同时产生出来,使用工厂方法模式可以将类B虚拟出来,避免类A与类B的耦合。
- 工厂方法的应用实例
日志记录器
日常我们的项目中都会用到日志记录器,我们的日志记录器可以支持多种方式记录日志,例如支持将日志记录到文件中,同时也支持将日志记录到数据库中。
我们看一下使用工厂方法如何设计:
抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是一种比较常用的模式。
抽象工厂是指抽象工厂模式(Abstract Factory Pattern)是一种比较常用的模式。
- 抽象工厂包含的角色
抽象工厂的角色和工厂方法模式的角色是一样的。
- AbstractFactory:抽象工厂该角色是抽象工厂模式的核心,与应用系统无关,任何创建对象的工厂类必须实现这个接口。
- ConcreteFactory:具体工厂该角色实现了抽象工厂接口,含有选择合适的产品对象的逻辑,并且受到应用程序的调用以创建产品对象。
- AbstractProduct:抽象产品该角色实现了抽象工厂接口,含有选择合适的产品对象的逻辑,并且受到应用程序的调用以创建产品对象。
- Product:具体产品该角色实现了抽象工厂接口,含有选择合适的产品对象的逻辑,并且受到应用程序的调用以创建产品对象。
角色的类图如下:
- 抽象工厂模式的优点
抽象工厂模式是工厂方法模式的进一步抽象,针对的是一族产品。如果产品族中只有一种产品,则抽象工厂模式就退化为工厂方法模式。除了工厂方法模式的优点外,抽象工厂模式还具有下列优点。
- 产品族内的约束为非公开状态,在不同的工厂中,各种产品可能具有不同的相互依赖关系,这些依赖关系由工厂封装在其内部,对于工厂的使用者是不可见的。
- 生产线的扩展非常容易,如果要针对同一产品族建立新的生产线,只需要实现产品族中的所有产品接口并建立新的工厂类即可。
- 抽象工厂模式的缺点
抽象工厂模式的最大缺点就是产品族本身的扩展非常困难,如果需要在产品族中增加一个新的产品类型,则需要修改多个接口,并且会影响已有的工厂类。
- 抽象工厂模式的适用场景
在以下情况下可以使用抽象工厂模式:
- 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。
- 系统中有多于一个的产品族,而每次只使用其中某一产品族。
- 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
- 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
- “开闭原则”的倾斜性
- “开闭原则”要求系统对扩展开放,对修改封闭,通过扩展达到增强其功能的目的。对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:
- 增加产品族:对于增加新的产品族,工厂方法模式很好的支持了“开闭原则”,对于新增加的产品族,只需要对应增加一个新的具体工厂即可,对已有代码无须做任何修改。
- 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,不能很好地支持“开闭原则”。
工厂模式在Spring中的应用
Spring最重要的两大特性莫过于IOC控制反转和AOP面向切面编程了。IOC的核心其实是DefaultListableBeanFactory这个对象。BeanFactory意思就是bean工厂,也就是对工厂模式的应用,可以说IOC就是工厂模式的应用。
我们看一下DefaultListableBeanFactory这个对象类图:
是不是有种很熟悉的感觉?由于篇幅有限,下次我们单独开一篇文章来讲Spring中对工厂模式的具体设计。
我是Seven,一个不懈努力的程序猿,希望本文能对你有所裨益