抽象工厂模式
抽象工厂模式:为创建一组相关或相互依赖的对象提供一个接口,而无需指定它们的具体类。
首先给出抽象工厂模式的通用类图:
在我第一次看到这个类图的时候,“我靠,这和工厂方法模式有啥区别,多了一个场景类Client?”。这个类图是《设计模式之禅》中的一张图,看完之后明白了这张图。
抽象工厂模式简单理解:抽象工厂模式的工厂接口定义了“一组方法”,而工厂方法模式的工厂接口定义了“一个”方法。(作为初学者,这样理解比较简单)
抽象工厂接口中的“一组”方法,用来创建定义中说的“一组”相关或相互依赖的对象
怎么理解相关和相互依赖呢?也可以简单的理解外在代码层面有关或无关的对象。代码层面无关,不代表它两真的无关。
举个栗子
假设有一个程序,其中包含了对文件的操作,假设当前的操作系统是windows,现在要将这个程序迁移到linux。如果使用抽象工厂模式,只需要修改工厂对象即可(如果写在配置文件中,只需要把工厂类的类名修改即可),如下图:
package AbstractFactory;
interface IOFactory {
InputStream getInputStream();
OutputStream getOutputStream();
}
interface InputStream {
void write();
}
interface OutputStream {
void print();
}
class WindowsIOFactory implements IOFactory {
@Override
public InputStream getInputStream() {
return new WindowsInputStream();
}
@Override
public OutputStream getOutputStream() {
return new WindowsOutputStream();
}
}
class WindowsInputStream implements InputStream {
@Override
public void write() {
System.out.println("Windows输入流");
}
}
class WindowsOutputStream implements OutputStream {
@Override
public void print() {
System.out.println("Windows输出流");
}
}
public class Client {
IOFactory factory = new WindowsIOFactory();
InputStream input = factory.getInputStream();
OutputStream output = factory.getOutputStream();
}
现在,要将Windows的IO流变为Linux的IO流;只需要按照上面的类图,实现一个Linux的工厂,用来创建Linxu的IO流,然后在实现Linux的产品(Linux的IO流),对于场景类,仅需要修改创建的工厂就。
这样就完美了吗?如果上层的依赖很多,一句一句的改是有风险的,所以,可以再次进行改进,客户端可以不关心IOFactory的具体类型,想到了什么?还可以用工厂方法模式来创建这个工厂,我们试着用简单工厂模式进行解耦。
假设有这样的配置文件
<bean>
<interface>IOFactory</interface>
<class>WindowsIOFactory</class>
</bean>
简单工厂模式就可以读取这个文件,来创建对应的工厂对象,所以,对于上面的迁移问题,修改这里的具体类就可以。
用伪代码实现一下:
public class CreatFactory {
public static getFactory(){
//读取配置文件
//找到IOFactory接口对应的具体类的类名className
//通过反射创建对象
IOFactory factory = Class.forName(className).newInstance();
//现在newInstance()已经不推荐使用了,伪代码不必要纠结
return factory;
}
}
如果场景类使用这个简单工厂模式,则不用关心具体的实现类,实现解耦,更换操作系统时代码都不用修改了。
public class Client {
IOFactory factory = CreatFactory.getFactory();
InputStream input = factory.getInputStream();
OutputStream output = factory.getOutputStream();
}
回过头来看定义
额,扯远了,再回来看抽象工厂模式。
通过上面的例子,应该理解了“创建一组相关对象”,上面例子中的相关对象就是输入流对象和输出流对象,输入流和输出流的相关关系就是它们的对应的操作系统相同。对于不同的操作系统,就会有不同的工厂来创建相应的一组对象。
产品族和产品等级
如图,同一个工厂生产的一组对象构成一个产品族;不同工厂生产的同类产品构成一个产品等级。上面的例子中,Windows平台下的WindowsInputStream对象和WindowsOutputStream构成一个产品族。
抽象工厂模式的优缺点
优点
- 封装性和隔离性。和工厂方法模式一样,上层模块只关心接口,不关心对象创建细节,也不关心对象的具体类型。
- 对产品族进行扩展很简单,实现新的工厂和新的产品即可(就像上面的那个例子)
缺点
产品等级扩展困难,扩展时破坏开闭原则。
使用场景
- 产品族多余一个,系统每次只使用一个。
- 属于同一个产品族的产品一起使用。