java反射抽象工厂模式_抽象工厂模式(JAVA反射)

实例代码(JAVA):模式动机

在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。

为了更清晰地理解工厂方法模式,需要先引入两个概念:

? 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。

? 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。

产品族与产品等级结构示意图:

20190111003745488507.png

当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。

抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态。

抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。

20190111003745629137.png

模式定义

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。

模式结构

20190111003745719961.png

抽象工厂模式包含如下角色:

? AbstractFactory:抽象工厂

? ConcreteFactory:具体工厂

? AbstractProduct:抽象产品

? Product:具体产品

模式分析

20190111003745943602.png

20190111003746052005.png

抽象工厂类的典型代码如下:

1 public abstract classAbstractFactory2 {3 public abstractAbstractProductA createProductA();4 public abstractAbstractProductB createProductB();5 }

具体工厂类的典型代码如下:

1 public class ConcreteFactory1 extendsAbstractFactory2 {3 publicAbstractProductA createProductA()4 {5 return newConcreteProductA1();6 }7 publicAbstractProductB createProductB()8 {9 return newConcreteProductB1();10 }11 }

模式实例与解析

实例一:电器工厂

? 一个电器工厂可以产生多种类型的电器,如海尔工厂可以生产海尔电视机、海尔空调等,TCL工厂可以生产TCL电视机、TCL空调等,相同品牌的电器构成一个产品族,而相同类型的电器构成了一个产品等级结构,现使用抽象工厂模式模拟该场景。

20190111003746176033.png

实例代码(JAVA):

1 //抽象产品 Television

2 public interfaceTelevision3 {4 public voidplay();5 }6

7 //具体产品 HaierTelevision

8 public class HaierTelevision implementsTelevision9 {10 public voidplay()11 {12 System.out.println("海尔电视机播放中......");13 }14 }15

16 //具体产品 TCLTelevision

17 public class TCLTelevision implementsTelevision18 {19 public voidplay()20 {21 System.out.println("TCL电视机播放中......");22 }23 }24

25 //抽象产品 AirConditioner

26 public interfaceAirConditioner27 {28 public voidchangeTemperature();29 }30

31 //具体产品 HaierAirConditioner

32 public class HaierAirConditioner implementsAirConditioner33 {34 public voidchangeTemperature()35 {36 System.out.println("海尔空调温度改变中......");37 }38 }39

40 //具体产品 TCLAirConditioner

41 public class TCLAirConditioner implementsAirConditioner42 {43 public voidchangeTemperature()44 {45 System.out.println("TCL空调温度改变中......");46 }47 }48

49 //抽象工厂 EFactory

50 public interfaceEFactory51 {52 publicTelevision produceTelevision();53 publicAirConditioner produceAirConditioner();54 }55

56 //具体工厂 HaierFactory

57 public class HaierFactory implementsEFactory58 {59 publicTelevision produceTelevision()60 {61 return newHaierTelevision();62 }63

64 publicAirConditioner produceAirConditioner()65 {66 return newHaierAirConditioner();67 }68 }69

70 //具体工厂 TCLFactory

71 public class TCLFactory implementsEFactory72 {73 publicTelevision produceTelevision()74 {75 return newTCLTelevision();76 }77

78 publicAirConditioner produceAirConditioner()79 {80 return newTCLAirConditioner();81 }82 }83

84 //配置文件 config.xml

85 <?xml version="1.0"?>

86

87 HaierFactory

88

89

90 //通过反射获得具体工厂的实例 XMLUtil

91 import javax.xml.parsers.*;92 import org.w3c.dom.*;93 importorg.xml.sax.SAXException;94 import java.io.*;95 public classXMLUtil96 {97 //该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象

98 public staticObject getBean()99 {100 try

101 {102 //创建文档对象

103 DocumentBuilderFactory dFactory =DocumentBuilderFactory.newInstance();104 DocumentBuilder builder =dFactory.newDocumentBuilder();105 Document doc;106 doc = builder.parse(new File("config.xml"));107

108 //获取包含类名的文本节点

109 NodeList nl = doc.getElementsByTagName("className");110 Node classNode=nl.item(0).getFirstChild();111 String cName=classNode.getNodeValue();112

113 //通过类名生成实例对象并将其返回

114 Class c=Class.forName(cName);115 Object obj=c.newInstance();116 returnobj;117 }118 catch(Exception e)119 {120 e.printStackTrace();121 return null;122 }123 }124 }125

126 //客户端类 Client

127 public classClient128 {129 public static voidmain(String args[])130 {131 try

132 {133 EFactory factory;134 Television tv;135 AirConditioner ac;136 factory=(EFactory)XMLUtil.getBean();137 tv=factory.produceTelevision();138 tv.play();139 ac=factory.produceAirConditioner();140 ac.changeTemperature();141 }142 catch(Exception e)143 {144 System.out.println(e.getMessage());145 }146 }147 }

实例代码(C++):

1 //抽象工厂模式

2 #include

3 using namespacestd;4

5 //抽象产品类 Television

6 classTelevision7 {8 public:9 virtual void play() = 0;10 };11

12 //具体产品类 HaierTelevision

13 class HaierTelevision:publicTelevision14 {15 public:16 void play() override

17 {18 cout << "海尔电视播放中..." <

22 //具体产品类 TCLTelevision

23 class TCLTelevision : publicTelevision24 {25 public:26 void play() override

27 {28 cout << "TCL电视播放中..." <

32 //抽象产品 AirConditioner

33 classAirConditioner34 {35 public:36 virtual void changeTemperature() = 0;37 };38

39 //具体产品 HaierAirConditioner

40 class HaierAirConditioner : publicAirConditioner41 {42 public:43 void changeTemperature() override

44 {45 cout << "海尔空调温度改变中..." <

49 //具体产品 TCLAirConditioner

50 class TCLAirConditioner : publicAirConditioner51 {52 public:53 void changeTemperature() override

54 {55 cout << "TCL空调温度改变中..." <

59 //抽象工厂 EFactory

60 classEFactory61 {62 public:63 virtual Television* productTelevision() = 0;64 virtual AirConditioner* productAirConditioner() = 0;65 };66

67 //具体工厂 HaierFactory

68 class HaierFactory : publicEFactory69 {70 public:71 Television* productTelevision() override

72 {73 return newHaierTelevision();74 }75

76 AirConditioner* productAirConditioner() override

77 {78 return newHaierAirConditioner();79 }80 };81

82 //具体工厂 TCLFactory

83 class TCLFactory : publicEFactory84 {85 public:86 Television* productTelevision() override

87 {88 return newTCLTelevision();89 }90

91 AirConditioner* productAirConditioner() override

92 {93 return newTCLAirConditioner();94 }95 };96

97 //客户端

98 intmain()99 {100 EFactory*factory;101 Television*tv;102 AirConditioner*ac;103 factory = newHaierFactory();104 tv = factory->productTelevision();105 tv->play();106 ac = factory->productAirConditioner();107 ac->changeTemperature();108

109 factory = newTCLFactory();110 tv = factory->productTelevision();111 tv->play();112 ac = factory->productAirConditioner();113 ac->changeTemperature();114 return 0;115 }

运行结果:

20190111003746420183.png

实例二:数据库操作工厂

? 某系统为了改进数据库操作的性能,自定义数据库连接对象Connection和语句对象Statement,可针对不同类型的数据库提供不同的连接对象和语句对象,如提供Oracle或SQL Server专用连接类和语句类,而且用户可以通过配置文件等方式根据实际需要动态更换系统数据库。使用抽象工厂模式设计该系统。

20190111003746532492.png

模式优缺点

优点

? 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。

? 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。

? 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。

缺点

? 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。

? 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)

模式适用环境

在以下情况下可以使用抽象工厂模式:

? 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。

? 系统中有多于一个的产品族,而每次只使用其中某一产品族。

? 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。

? 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

模式应用

(1) Java SE AWT(抽象窗口工具包)

? 在Java语言的AWT(抽象窗口工具包)中就使用了抽象工厂模式,它使用抽象工厂模式来实现在不同的操作系统中应用程序呈现与所在操作系统一致的外观界面。

(2) 在很多软件系统中需要更换界面主题,要求界面中的按钮、文本框、背景色等一起发生改变时,可以使用抽象工厂模式进行设计。

模式扩展

“开闭原则”的倾斜性

? “开闭原则”要求系统对扩展开放,对修改封闭,通过扩展达到增强其功能的目的。对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:

? (1) 增加产品族:对于增加新的产品族,工厂方法模式很好的支持了“开闭原则”,对于新增加的产品族,只需要对应增加一个新的具体工厂即可,对已有代码无须做任何修改。

? (2) 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,不能很好地支持“开闭原则”。

? 抽象工厂模式的这种性质称为“开闭原则”的倾斜性,抽象工厂模式以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,但不能为新的产品等级结构的增加提供这样的方便。

工厂模式的退化

? 当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值