抽象工厂模式简述
在了解抽象工厂模式前,需要先理解两个概念,"产品族","产品等级结构",这两者是抽象工厂中的重要构成,也是判断应用场景是否符合抽象工厂的条件之一。
产品等级结构
产品等级结构即产品的继承结构,例如一个抽象类是电视,那么他的子类有LG电视机,三星电视机,索尼电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
产品族
在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如LG工厂生产的LG电视机和LG冰箱。LG电视机位于电视机产品等级结构中,LG冰箱位于冰箱产品等级结构中,LG电视和LG冰箱组成了产品族。
图示
不同颜色的多个正方形、圆形和椭圆形分别构成了三个不同的产品等级结构,而相同颜色的正方形、圆形和椭圆形构成了一个产品族,每一个形状对象都位于某个产品族,并属于某个产品等级结构。图中一共有五个产品族,分属于三个不同的产品等级结构。只要指明一个产品所处的产品族以及它所属的等级结构,就可以唯一确定这个产品。
抽象工厂和工厂方法的区别
抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。
抽象工厂的"开闭原则倾斜性"
在抽象工厂模式中,增加新的产品族很方便,但是增加新的产品等级结构很麻烦,抽象工厂模式的这种性质称为“开闭原则”的倾斜性。抽象工厂模式无法解决该问题,这也是抽象工厂模式最大的缺点。正因为抽象工厂模式存在“开闭原则”的倾斜性,它以一种倾斜的方式来满足“开闭原则”,为增加新产品族提供方便,但不能为增加新产品结构提供这样的方便,因此要求设计人员在设计之初就能够全面考虑,尽量不对产品结构等级进行改动。
抽象工厂总结
抽象工厂模式是工厂方法模式的进一步延伸,由于它提供了功能更为强大的工厂类并且具备较好的可扩展性,在软件开发中得以广泛应用,尤其是在一些框架和API类库的设计中,例如在Java语言的AWT(抽象窗口工具包)中就使用了抽象工厂模式,它使用抽象工厂模式来实现在不同的操作系统中应用程序呈现与所在操作系统一致的外观界面。抽象工厂模式也是在软件开发中最常用的设计模式之一。
优点
-
抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。
-
当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
-
增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。
缺点
- 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。
示例
有一款跨平台的软件,可以针对Windows,Mac适配,该软件现有一个界面,可以设置按钮和字体,软件要求具有较好的扩展性以支持新的操作系统平台。
示例UML图
示例代码
//按钮接口
public interface Button {
void display();
}
//字体接口
public interface Font {
void display();
}
//抽象工厂接口
public interface Factory {
Button createButton();
Font createFont();
}
//Windows平台实现按钮
public class WindowsButton implements Button {
@Override
public void display() {
System.out.println("显示Windows按钮");
}
}
//Windows平台实现字体
public class WindowsFont implements Font{
@Override
public void display() {
System.out.println("显示Windows字体");
}
}
//Windows平台的工厂类
public class WindowsFactory implements Factory{
@Override
public Button createButton() {
System.out.println("生产Windows按钮");
return new WindowsButton();
}
@Override
public Font createFont() {
System.out.println("生产Windows字体");
return new WindowsFont();
}
}
//客户端调用,采用XML读取配置文件的形式,获取具体的工厂类
public static void main(String[] args) {
Button button;
Font font;
Factory factory = ((Factory) XMLUtil.getBean());
if (factory != null) {
button = factory.createButton();
font = factory.createFont();
button.display();
font.display();
}
}
网友评论