提供一个接口以创建一系列相关或互相依赖的对象,而无须指定它们具体的类
抽象工厂 相当于一个图纸,一个说明产品需要哪些组件的图纸
她的目的在于当你需要一系列相互关联或存在协作关系的对象的时候,你可以在一个抽象工厂对象中找到你所需的所有对象的产出方法
对于一个APP来说,他的组件风格常常是同一个系列的。
比如说:
我现在有一个桌面应用,我希望GUI上的 Button(按钮) 和 TextArea(文本框) 的默认样式是一致的。于是,我建立了 ButtonFactory
和 TextAreaFactory
这两个工厂类来生成按钮和文本框,就像这样:
public class ButtonFactory{
public Button createButton(){
Button btn = new Button();
做一些属性设定
return btn;
}
}
public class TextAreaFactory{
public TextArea createTextArea(){
TextArea ta = new TextArea();
做一些属性设定
return ta;
}
}
这样一来我在程序里就可以通过这两个工厂类来产出默认样式一致的按钮和文本框
现在新业务来了,应用提供了 明亮主题
和 暗黑主题
两种主题以供用户切换,那么按钮和文本框也需要新增明亮版本和暗黑版本,就像这样:
public class ButtonFactory{
public Button createLightButton(){
return 明亮主题的按钮对象;
}
public Button createDarkButton(){
return 暗黑主题的按钮对象;
}
}
public class TextAreaFactory{
public TextArea createLightTextArea(){
return 明亮主题的文本区域对象;
}
public TextArea createDarkTextArea(){
return 暗黑主题的文本区域对象;
}
}
很显然,这个设计是糟糕的,因为在这种情况下我们创建一个组件是硬编码。在引入主题的情况下,我们必须要用这样的流程来创建一个组件:
查询当前样式 -> 根据查询结果进行 if-else 判断 -> 符合条件则调用对应的create方法
可能你会说,我可以用 参数化的工厂方法 把这些if-else都集中到工厂类里面去做呀
这两种做法其实没有什么区别,都是在主题发生变化的时候,你必须要去修改已经写好的代码
在设计模式中有一个原则叫
开放-关闭原则
开放-关闭原则
类应该对拓展开放,对修改关闭
我们定义一个不提供实现的组件工厂
,就像这样:
public interface ComponentFactory{
//创建一个按钮
Button createButton();
//创建一个文本区域
TextArea createTextArea();
}
然后我们根据不同的主题,为他创建实例类,就像这样:
public interface ComponentFactory{
//创建一个按钮
Button createButton();
//创建一个文本区域
TextArea createTextArea();
}
//明亮主题的组件工厂
public class LightComponentFactory implements ComponentFactory{
//创建明亮主题按钮
public Button createButton(){
return 明亮主题的按钮对象;
}
//创建明亮主题的文本区域对象
public TextArea createTextArea(){
return 明亮主题的文本区域对象;
}
}
//暗黑主题的组件工厂
public class DarkComponentFactory implements ComponentFactory{
//创建暗黑主题按钮
public Button createButton(){
return 暗黑主题的按钮对象;
}
//创建暗黑主题的文本区域对象
public TextArea createTextArea(){
return 暗黑主题的文本区域对象;
}
}
外部代码只会和 ComponentFactory交互,而对具体调用了哪一种主题的 组件工厂 一无所知,就像这样:
…… client ……
ComponentFactory componentFactory;
//设定明亮主题
public void setLightTheme(){
componentFactory = new LightComponentFactory();
}
//设定暗黑主题
public void setDarkTheme(){
componentFactory = new DarkComponentFactory();
}
……
Button btn = componentFactory.createButton();
TextArea ta = componentFactory.createTextArea();
……
用户在切换主题的时候,程序实质上是切换了当前产出组件的具体工厂(同样,外部代码还是对这个动作一无所知)
如果以后要拓展新的主题,那就更简单了,只需要新增ComponentFactory的子类就可以了,完全不需要修改已有的代码
于是乎,我们得到了下面这样的结构:
而这是一个标准的抽象工厂实现
初学设计模式的时候,很多道友都会对抽象工厂模式的存在感觉到疑惑,特别是在工厂方法随处可见的情况下。
但是抽象工厂和工厂模式真的是分管不同部分的两个模式
因为一个抽象工厂的作用,往往是用来对一群工厂类簇进行管理
比如说:
组装一台电脑至少需要主板、CPU、电源、内存条和硬盘。但并不是所有型号硬件都是互相兼容的,即使是相同型号也有品牌之分,你如果自己买零件攒电脑呢,就是这样:
而现在有一些厂商/商家,他会直接卖给你整机,你到手就能用。注意,这些商家可不是自己生产的所有部件,他是到生产单个零件的工厂里采购的。也就是说,他帮你攒了一个电脑,但是他保证里面的部件都是兼容的,就像这样:
这时候,生产单独零件的厂商就相当于工厂类;直接卖整机的商家就相当于抽象工厂。
事实上不只是抽象工厂,还包括工厂方法模式。工厂类通常是没有状态的,只负责不断的产出产品
因此,为了节约资源,工厂类通常都是单例的(即整个程序用同一个对象)