抽象工厂模式
其它创建型模式链接:
产品等级结构与产品族
产品等级结构:产品等级结构即产品的继承结构,例如一个抽象类是电视机,其子类包括海尔电视机,海信电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构。
产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的位于不同产品等级结构中的一组产品,例如海尔电器工厂生产的海尔电视机,海尔冰箱,海尔电视机位于电视机产品等级结构中,海尔冰箱位于冰箱产品等级结构中,海尔冰箱和海尔电视机构成一个产品族。
抽象工厂模式概述
抽象工厂模式是所有形式工厂模式中最为抽象和最具一般性的一种你那个形式。抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。
抽象工厂模式为创建一组对象提供了一种解决方案。与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一族产品。
具体定义如下:
抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
抽象工厂模式结构
- AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
- ConcreateFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
- AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所有的业务方法。
- ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
案例
在每个系统都有由图形构件组成的构件家族,可以通过一个抽象角色给出功能定义,而由具体子类给出不同操作系统下的具体实现,例如系统中包含两个产品等级结构,分别是Button和Text;同时,包含三个产品系,即UNIX家族,Linux家族与Windows家族。
使用抽象工厂模式来设计并实现该结构
结构图
代码实现
抽象产品类
public interface Button {
void display();
}
public interface Text {
void display();
}
具体产品类
public class LinuxButton implements Button{
@Override
public void display() {
System.out.println("显示LinuxButton");
}
}
public class UNIXButton implements Button {
@Override
public void display() {
System.out.println("显示UNIXButton");
}
}
public class WindowsButton implements Button{
@Override
public void display() {
System.out.println("显示WindowsButton");
}
}
public class LinuxText implements Text{
@Override
public void display() {
System.out.println("显示LinuxText");
}
}
public class UNIXText implements Text{
@Override
public void display() {
System.out.println("显示UNIXText");
}
}
public class WindowsText implements Text{
@Override
public void display() {
System.out.println("显示WindowsText");
}
}
抽象工厂
public interface GraphicFactory {
Button createButton();
Text createText();
}
具体工厂
public class LinuxGraphicFactory implements GraphicFactory{
@Override
public Button createButton() {
return new LinuxButton();
}
@Override
public Text createText() {
return new LinuxText();
}
}
public class UNIXGraphicFactory implements GraphicFactory{
@Override
public Button createButton() {
return new UNIXButton();
}
@Override
public Text createText() {
return new UNIXText();
}
}
public class WindowsGraphicFactory implements GraphicFactory{
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public Text createText() {
return new WindowsText();
}
}
工具类
读取xml文件的类名,创建具体工厂
<config>
<className>abstractFactory.WindowsGraphicFactory</className>
</config>
public class XmlUtil {
public static Object getBean(){
try {
//创建文档对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File("src//main//resources//designPatterns//simpleFactory//config.xml"));
//获取节点
NodeList nodeList = document.getElementsByTagName("className");
Node node = nodeList.item(0).getFirstChild();
String className= node.getNodeValue().trim();
Class<?> c = Class.forName(className);
return c.newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
客户端
public class Demo {
public static void main(String[] args) {
GraphicFactory factory;
Button button;
Text text;
factory=(GraphicFactory) XmlUtil.getBean();
button= factory.createButton();
text= factory.createText();
button.display();
text.display();
}
}
效果
显示WindowsButton
显示WindowsText
抽象工厂优/缺点与适用环境
抽象工厂模式是工厂方法模式的进一步延伸,由于它提供了功能更为强大的工厂类并且具备良好的可扩展性,在软件开发中得到了广泛的应用,尤其是在一些框架和API类库设计中。
抽象工厂优点
抽象工厂的优点如下:
- 抽象工厂模式隔离了具体类的生成,使得客户端并不需要知道什么被创建。由于被隔离,更换一种具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的公共接口,因此只要改变具体工厂实例就可以在某种程度上改变整个系统的行为。
- 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
- 增加新的产品族很方便,无需修改已有系统,符合开闭原则。
抽象工厂缺点
抽象工厂缺点如下:
- 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了开闭原则。
抽象工厂的适用环境
在以下情况下可以考虑使用抽象工厂模式:
- 一个系统不应该当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是很重要的,用户无需关心对象的创建过程,将对象的创建过程,将对象的创建和使用解耦。
- 系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来使用户能够动态的改变产品族,也可以很方便地增加新的产品族。
- 属于同一个产品族的产品将在一起使用,这一约束必须在系统设计中体现出来。同一产品族中的产品可以是没有任何关系的对象,但是它们都具有一些共同的约束。例如统一系统下的按钮和文本框,按钮和文本框之间没有任何直接关系,但是它们都属于同一系统,此时具有一个共同的约束条件,即操作系统的类型。
- 产品的等级结构稳定,在设计完成之后不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。
开闭原则的倾斜性
抽象工厂无法解决增加产品等级结构时的弊端,这也是抽象工厂模式最大的缺点。在抽象工厂模式中增加新的产品族很方便,但是增加新的产品等级结构很麻烦,抽象工厂模式的这种性质称为开闭原则的倾斜性。
开闭原则要求对拓展开放,对修改关闭,通过拓展达到增强功能的目的,对于设计多个产品族和多个产品等级结构的系统,其功能增强包括增加产品族和增加新的产品等级结构两方面。
正因为抽象工厂模式存在开闭原则的倾斜性,它以一种倾斜的方式为增加产品族提供便利,但不能为增加产品等级结构提供这样的便利,这就要求设计人员在设计之初就能够考虑全面。
构时的弊端,这也是抽象工厂模式最大的缺点。在抽象工厂模式中增加新的产品族很方便,但是增加新的产品等级结构很麻烦,抽象工厂模式的这种性质称为开闭原则的倾斜性。
开闭原则要求对拓展开放,对修改关闭,通过拓展达到增强功能的目的,对于设计多个产品族和多个产品等级结构的系统,其功能增强包括增加产品族和增加新的产品等级结构两方面。
正因为抽象工厂模式存在开闭原则的倾斜性,它以一种倾斜的方式为增加产品族提供便利,但不能为增加产品等级结构提供这样的便利,这就要求设计人员在设计之初就能够考虑全面。