06、工厂模式-工厂方法模式

方法工厂模式要比对着简单工厂模式学习。
在简单工厂中已经说到了,简单工厂模式有个弊端:
假如我的系统要进行扩展,需新增产品类的时候,除了新增一个产品类之外,还需要对工厂类进行调整,这不符合OCP。
那么接下来看下 工厂 方法模式是怎么解决这个问题的。
依然使用上面的例子:
首先定义抽象类People以及创建抽象类People的工厂类--姑且叫做 PeopleCraetor吧,Factory这个单词就不再体现了。如下:
   
  1. package com.yp.learn.designmodel;
  2. public abstract class People {
  3. abstract void say();
  4. }
  5. package com.yp.learn.designmodel;
  6. public abstract class PeopleCreator {
  7. public abstract People createPeople();
  8. }
之后定义类中国人,美国人,并且此两个类都继承了 People类。如下:
   
  1. package com.yp.learn.designmodel;
  2. public class Chinese extends People {
  3. @Override
  4. void say() {
  5. System.out.println("说汉语");
  6. }
  7. }
  8. package com.yp.learn.designmodel;
  9. public class American extends People {
  10. @Override
  11. void say() {
  12. System.out.println("Say American English");
  13. }
  14. }
然后为这两个类创建工厂,即专门生成这两个类的工厂,并且这个工厂继承了PeopleCreator类。如下:
   
  1. package com.yp.learn.designmodel;
  2. public class AmericanCreator extends PeopleCreator {
  3. @Override
  4. public People createPeople() {
  5. // TODO Auto-generated method stub
  6. return new American();
  7. }
  8. }
  9. package com.yp.learn.designmodel;
  10. public class ChineseCreator extends PeopleCreator {
  11. @Override
  12. public People createPeople() {
  13. // TODO Auto-generated method stub
  14. return new Chinese();
  15. }
  16. }
整个类的列表截图如下:

最后,再看下客户端代码:
   
  1. package com.yp.learn.designmodel;
  2. public class Start {
  3. public static void main(String[] args) {
  4. // TODO Auto-generated method stub
  5. People p ;//定义抽象类变量
  6. PeopleCreator peopleCreator ;//定义抽象类工厂变量
  7. peopleCreator = new ChineseCreator();//依据实际业务而言所调用的实际产品工厂类。
  8. p = peopleCreator.createPeople();
  9. peopleCreator = new AmericanCreator();
  10. p.say();
  11. p = peopleCreator.createPeople();
  12. p.say();
  13. }
  14. }

运行结果:


分析:
现在看下客户端中,涉及到了哪些类:
1、抽象类People:此类包含对产品类方法的抽象,通过此类,结合Java多态的特性,实现一个变量依据不同的实现,产生不同的行为。如例子中p被实现了两次,但是其执行相同方法say的结果却不同。
2、创建抽象类People的工厂:用定义生产抽象类People的工厂,如例子中,负责定义抽象类实例的引用。但是实现却由其子类完成。
3、创建实际产品的工厂类,用于生成具体实现产品类的工厂类。

假如 ,我现在需要对软件扩展,需要新增法国人,那么,我所需要做的则如下:
1、新增一个Franch,继承People
2、新增一个FranchCreator,继承PeopleCreator
3、在客户端的代码中,对于变量 peopleCrator的赋值,调整为 peopleCreator = FranchCreator();
其余都不变动。

现在比较一下,原有的业务逻辑,即涉及到中国人及工厂类和美国人及其工厂类的代码,没有发生过变动,而系统的拓展,只是通过新增类的方式实现。这已经将简单工厂模式的弊端给解决了



可能会有疑问:
1、客户端代码还是变了,还是不符合OCP
答:客户端是随着实际需求所变动的,因此不可能控制客户端的代码不发生变动,除非客户的需求永远不变,因此,OCP所指的是针对业务层的代码而非客户端的代码。实现以不变(软件的业务层的模式)应万变(客户需求)。
2、客户端代码中,以中国人和美国人进行了举例,也就是说,客户端中知道是需要要哪个实例,那么这个时候,为什么不直接使用new关键字实例对象,反而这么麻烦?
答:这种疑问是正常的,但是这个时候要考虑的就是要从软件设计的角度去看待问题而非从代码实现上去看待。工厂模式的意图在于解耦,即 对象创建不应该由客户端中体现。因为客户端所关注的,是使用而非创建。但是使用之前必须存在创建,那么工厂方法模式就是把创建的部分交给了工厂类,客户端代码直接使用相关的产品类就行。但是同时也引入了在客户端中创建工厂类的这种情况。不过通过比较,在客户端创建工厂类和在客户端创建产品类,会发现前者的灵活性更加的好。
学习模式一定要注意,学习的不是代码的实现,而是对设计的理解。
3、虽然与简单工厂模式相比,解决了OCP,但是,简单工厂模式,只需要在客户端创建一个工厂类就行,然后通过工厂类的方法传入参数,可获得产品类,但是工厂方法模式,貌似并没有这种简单的方式,而是必须通过指定的产品工厂类来实例化抽象工厂类,那么客户端岂不是还是存在要判断到底该选择哪种产品工厂类?也就是说,客户端代码还需要去维护客户所选择的内容与所选内容所对应的产品类之间的一个映射关系?
答:此问题正是工厂方法模式的弊端。的确,比较简单工厂模式,工厂方法模式的确存在这样的问题,任何一种模式绝对不可能消除条件判断,只能说将条件判断转移。



总结:
1、静态工厂模式,实现了解耦,但是不遵循OCP
2、工厂方法模式,实现了OCP,但是解耦并没有静态工厂模式完成的好

如果要针对以上两个问题共同解决,会通过Java的反射技术实现。这一点在 spring中表现的很突出。






转载于:https://my.oschina.net/u/1182369/blog/406569

猜你喜欢

转载自blog.csdn.net/weixin_34377919/article/details/92083695