文章类型: JAVA
关键词: 工厂模式及模板方法模式深度思考
内容摘要: 工厂模式及模板方法模式深度思考

工厂模式及模板方法模式深度思考

2016/8/25 16:13:32    来源:apple    阅读:

1.简单工厂 
郭大神和盘哥在说好想买ipad,用代码实现一下 
不用模式的设计 

Java代码

  1. public interface Product {  

  2.   

  3.     String getDesc();  

  4. }  

  5.   

  6. public class IpadProduct implements Product {  

  7.   

  8.     @Override  

  9.     public String getDesc() {  

  10.         return "Ipad2";  

  11.     }  

  12.   

  13. }  

  14.   

  15. public class Client {  

  16.   

  17.     public static void main(String[] args) {  

  18.         Product product = new IpadProduct();  

  19.         System.out.println("郭大神说好想买" + product.getDesc() + ",但没钱!!!");  

  20.         product = new IpadProduct();  

  21.         System.out.println("盘哥说我好想买" + product.getDesc() + ",但没钱!!!");  

  22.     }  

  23. }  


有何问题? 
如果想买的iphone5时怎么办? 
得找到所有new IpadProduct改成new IphoneProduct 
而且改的是客户端的代码 

应用模式的设计 

Java代码

  1. public class IphoneProduct implements Product {  

  2.   

  3.     @Override  

  4.     public String getDesc() {  

  5.         return "Iphone5";  

  6.     }  

  7. }  

  8. public class SimpleFactory {  

  9.   

  10.     public static Product getProdcut() {  

  11.         return new IpadProduct();  

  12.     }  

  13. }  

  14.   

  15. public class Client {  

  16.   

  17.     public static void main(String[] args) {  

  18.         Product product = SimpleFactory.getProduct();  

  19.         System.out.println("郭大神说好想买" + product.getDesc() + ",但没钱!!!");  

  20.         product = SimpleFactory.getProduct();  

  21.         System.out.println("盘哥说我好想买" + product.getDesc() + ",但没钱!!!");  

  22.     }  

  23. }  


无模式遇到的问题如何解决? 
只要在SimpleFactory.getProdcut()换成IphoneProdcut即可 
优点 
创建对象收拢,扩展性加强了。 
扩展时不需要修改客户端代码。 
对象创建与使用解耦 
缺点 
多出一个工厂类 

2.工厂方法 


应用工厂方法模式的设计 

Java代码

  1. abstract public class Person {  

  2.     private String name;  

  3.   

  4.     Person(String name){  

  5.         this.name = name;  

  6.     }  

  7.   

  8.     abstract Product getProduct();  

  9.   

  10.     public void say() {  

  11.         Product product = getProduct();  

  12.         System.out.println(name + "说我好想买" + product.getDesc() + ",但没钱!!!");  

  13.     }  

  14. }  

  15.   

  16. public class GuoPerson extends Person {  

  17.     public GuoPerson(){  

  18.         super("郭大神?);  

  19.     }  

  20.   

  21.     @Override  

  22.     Product getProduct() {  

  23.         return new IpadProduct();  

  24.     }  

  25. }  

  26.   

  27. public class ShenPerson extends Person {  

  28.     public ShenPerson(){  

  29.         super("盘哥");  

  30.     }  

  31.   

  32.     @Override  

  33.     Product getProduct() {  

  34.         return new IpadProduct();  

  35.     }  

  36. }  

  37.   

  38. public class ModeClient {  

  39.   

  40.     public static void main(String[] args) {  

  41.         Person person = new GuoPerson();  

  42.         person.say();  

  43.         person = new ShenPerson();  

  44.         person.say();  

  45.     }  

  46. }  


优点 
可以在不知道具体产品下实现编程 
可以在不改变业务代码上很容易扩展出一个新的产品 
缺点 
多出几个具体工厂类 

3.抽象工厂 
考虑一下生产ipad和iphone的一个程序 
工厂模式的设计有何问题? 

Java代码

  1. public interface Ipad extends Product {  

  2. }  

  3. public class HongKongIpad implements Ipad {  

  4.     @Override  

  5.     public String getDesc() {  

  6.         return "香港版的Ipad";  

  7.     }  

  8. }  

  9. public class USAIpad implements Ipad {  

  10.     @Override  

  11.     public String getDesc() {  

  12.         return "美国版的Iphone";  

  13.     }  

  14. }  

  15. public interface Iphone extends Product {  

  16. }  

  17. public class HongKongIphone implements Iphone {  

  18.     @Override  

  19.     public String getDesc() {  

  20.         return "香港版的Iphone";  

  21.     }  

  22. }  

  23. public class USAIphone implements Iphone {  

  24.     @Override  

  25.     public String getDesc() {  

  26.         return "美国版的Iphone";  

  27.     }  

  28. }  

  29. public class SimpleFactory {  

  30.     public static Ipad createIpad(int type) {  

  31.         if (type == 1) {  

  32.             return new HongKongIpad();  

  33.         }  

  34.   

  35.         return new USAIpad();  

  36.     }  

  37.   

  38.     public static Iphone createIphone(int type) {  

  39.         if (type == 1) {  

  40.             return new HongKongIphone();  

  41.         }  

  42.   

  43.         return new USAIphone();  

  44.     }  

  45. }  

  46. public class Client {  

  47.     public static void main(String[] args) {  

  48.             Ipad ipad = SimpleFactory.createIpad(1);  

  49.             Iphone iphone = SimpleFactory.createIphone(1);  

  50.             System.out.println("我采购的是:" + ipad.getDesc() + "和" + iphone.getDesc());  

  51. //            ipad = SimpleFactory.createIpad(2);  

  52. //            iphone =  SimpleFactory.createIphone(2);  

  53. //            System.out.println("我采购的是:" + ipad.getDesc() + "和" + iphone.getDesc());  

  54.     }  

  55. }  


工厂模式的设计有何问题? 
客户端想只买一家公司的产品,客户端需要了解每种类型是出自哪一家公司? 
港版ipad与iphone是出自同一家公司,美版ipad与iphone也是出自同一样公司,对于采购时 
它只要报一下要什么哪个品牌的就可以买到同一个品牌的ipad和iphone 

应用抽象工厂模式的设计 

Java代码

  1. public interface AppleFactory {  

  2.       

  3.     Ipad createIpad();  

  4.       

  5.     Iphone createIphone();  

  6. }  

  7. public class HongKongCompanyAppleFactory implements AppleFactory {  

  8.     @Override  

  9.     public Ipad createIpad() {  

  10.         return new HongKongIpad();  

  11.     }  

  12.   

  13.     @Override  

  14.     public Iphone createIphone() {  

  15.         return new HongKongIphone();  

  16.     }  

  17. }  

  18. public class USACompanyAppleFactory implements AppleFactory {  

  19.     @Override  

  20.     public Ipad createIpad() {  

  21.         return new USAIpad();  

  22.     }  

  23.   

  24.     @Override  

  25.     public Iphone createIphone() {  

  26.         return new USAIphone();  

  27.     }  

  28. }  

  29. public class ModeClient {  

  30.     public static void main(String[] args) {  

  31.         AppleFactory appleFactory = new HongKongCompanyAppleFactory();  

  32.         Ipad ipad = appleFactory.createIpad();  

  33.         Iphone iphone = appleFactory.createIphone();  

  34.         System.out.println("我采购的是:" + ipad.getDesc() + "和" + iphone.getDesc());  

  35. //        appleFactory = new USACompanyAppleFactory();  

  36. //        ipad = appleFactory.createIpad();  

  37. //        iphone = appleFactory.createIphone();  

  38. //        System.out.println("我采购的是:" + ipad.getDesc() + "和" + iphone.getDesc());  

  39.      }  

  40. }  


优点 

缺点 

深度思考 
spring容器是最大的工厂 
BeanFactory.getBean("xxx") 
FileSystemXmlApplicationContext/ClassPathXmlApplicationContext 

下面吐槽一下郭大神 
考虑一下郭大神的家谱 
... 
郭大神的祖父 

郭大神的父亲 

郭大神 

郭大神的儿子 
... 
郭大神的祖父创造了郭大神的父亲,郭大神的父新创造了郭大神,郭大神创造了郭大神的儿子 
盘哥这边呢 
... 
盘哥的祖父 

盘哥的父亲 

盘哥 

盘哥的儿子 
... 
用类来表示 

Java代码

  1. interface Grandfather{  

  2.     Father createFather();  

  3. }  

  4. interface Father{  

  5.     Self createSelf();  

  6. }  

  7. interface Self {  

  8.     Son createSon();  

  9. }  


如果我把郭明先生的祖父换成了姓郑(盘哥姓郑),则 
当我换掉Grandfather时,奇迹出现了,整个家族的姓都变了。 
从上面来看其实是工厂模式与工厂模式组合使用,经过组合后我们能写出具备极其扩展性的代码。 
上面的原理是把工厂抽象成是一个产品(就是把工厂也当成是产品,那么生产这个产品的就是工厂的工厂。),于是就出现了"工厂的工厂的工厂"生产出"工厂的工厂","工厂的工厂"生产"工厂",最后工厂生成产品。这样就是级联使用工厂。 
我们可以在任意一个环节替换实现,于是可以产生一个从大到小的扩展点。 

考虑一下我们的建站平台框架的设计 
站点有站点的接口, 同时还有站点资源接口(静态资源:js,css), 站点渲染接口, 站点数据接口。站点数据又可以分为站点数据读取接口, 和站点数据变更接口。 
如果我设计下面这样的一个接口 

Java代码

  1. interface SiteAPIFactory  

  2. {  

  3.     getSiteAPI();  

  4. }  

  5. interface SiteAPI{  

  6.   getSiteResourceAPI();  

  7.   getSiteDataAPI();  

  8.   getRenderAPI();  

  9. }  

  10. interface SiteDataAPI{  

  11.   getSiteDataReadAPI();  

  12.     getSiteDataDesignAPI();  

  13. }  

  14. interface SiteDataReadAPI{  

  15.     getSiteData();  

  16. }  

  17. interface SiteDataDesignAPI{  

  18.     updateSiteData();  

  19.     deleteSiteData();  

  20. }  


经过上面这样设计之后, 如果我替换了SiteAPIFactory的实现, 我就可以操控整个站点的所有接口实现, 当我只替换SiteDataAPI时我能控制站点读取与写入数据的实现。也就是说从大到小的粒点扩展点我都支持了。做为平台的设计, 应用就可以根据需要自行替换实现。从而达到各种粒度的扩展。 
很多模式都能组合起来使用,同时许多模式能与自身组合使用,像工厂,桥接等等 
同时如果我写个SiteAPIUtil的获取SiteAPIFacotry,于是我就能提供所有接口了 

Java代码

  1. SiteAPIUtil{  

  2.   SiteAPIFactory getSiteAPIFactory(){  

  3.       DefaultSiteAPIFactory.instance  

  4.   };  

  5.     SiteAPI getSiteAPI(){  

  6.         getSiteAPIFactory().getSiteAPI();  

  7.     };  

  8.     SiteDataAPI getSiteDataAPI(){  

  9.         getSiteAPI().getSiteDataAPI();  

  10.     };  

  11.     SiteDataDesignAPI getSiteDataDesignAPI(){  

  12.         getSiteDataAPI().getSiteDesignAPI();  

  13.     }  

  14.     ...  

  15. }  


再认真思考一下,你会发现SiteAPIUtil其实也是一个简单工厂,可以命名为SiteAPISimpleFactory 

4.模板方法 

考察一下郭大神与盘哥是如何上班的 
不用模式的设计 

Java代码

  1. public interface Person {  

  2.     String getName();  

  3.     void summary();  

  4. }  

  5.   

  6. public class GuoPerson implements Person {  

  7.     @Override  

  8.     public void summary() {  

  9.         System.out.println(getName() + "起床");  

  10.         System.out.println(getName() + "坐公交去上班");  

  11.         System.out.println(getName() + "上班到9点时上了一次厕所");  

  12.         System.out.println(getName() + "上班到10点时上了一次厕所");  

  13.         System.out.println(getName() + "上班到11点时上了一次厕所");  

  14.         System.out.println(getName() + "坐公交回到家");  

  15.         System.out.println(getName() + "洗个澡睡觉了");  

  16.     }  

  17.   

  18.     @Override  

  19.     public String getName() {  

  20.         return "郭大神";  

  21.     }  

  22. }  

  23.   

  24. public class ShenPerson implements Person {  

  25.     @Override  

  26.     public void summary() {  

  27.         System.out.println(getName() + "起床");  

  28.         System.out.println(getName() + "骑自行车去上班");  

  29.         System.out.println(getName() + "上班到10点时上了一次厕所");  

  30.         System.out.println(getName() + "骑自行车回到家");  

  31.         System.out.println(getName() + "洗个澡睡觉了");  

  32.     }  

  33.   

  34.     @Override  

  35.     public String getName() {  

  36.         return "盘哥";  

  37.     }  

  38. }  

  39.   

  40. public class Client {  

  41.     public static void main(String[] args) {  

  42.         Person person = new GuoPerson();  

  43.         person.summary();  

  44.         person = new ShenPerson();  

  45.         person.summary();  

  46.     }  

  47. }  


不用模式有何问题? 
他们两个上班过程基本上是一样的, 出现了重复的代码。 

再考察一个人得同样要写很多重复的代码。 
应用模式的设计 

Java代码

  1. abstract public class AbstractPerson implements Person {  

  2.   

  3.     public void summary() {  

  4.         System.out.println(getName() + "起床");  

  5.         goToCompany();  

  6.         work();  

  7.         backToHome();  

  8.         System.out.println(getName() + "洗个澡睡觉了");  

  9.     }  

  10.     abstract public void goToCompany();  

  11.     abstract public void work();  

  12.     abstract public void backToHome();  

  13. }  

  14. public class GuoPerson extends AbstractPerson {  

  15.     @Override  

  16.     public String getName() {  

  17.         return "郭大神";  

  18.     }  

  19.   

  20.     @Override  

  21.     public void goToCompany() {  

  22.         System.out.println(getName() + "坐公交去上班");  

  23.     }  

  24.   

  25.     @Override  

  26.     public void work() {  

  27.         System.out.println(getName() + "上班到9点时上了一次厕所");  

  28.         System.out.println(getName() + "上班到10点时上了一次厕所");  

  29.         System.out.println(getName() + "上班到11点时上了一次厕所");  

  30.     }  

  31.   

  32.     @Override  

  33.     public void backToHome() {  

  34.         System.out.println(getName() + "坐公交回到家");  

  35.     }  

  36. }  

  37. public class ShenPerson extends AbstractPerson {  

  38.     @Override  

  39.     public String getName() {  

  40.         return "盘哥";  

  41.     }  

  42.   

  43.     @Override  

  44.     public void goToCompany() {  

  45.         System.out.println(getName() + "骑自行车去上班");  

  46.     }  

  47.   

  48.     @Override  

  49.     public void work() {  

  50.         System.out.println(getName() + "上班到10点时上了一次厕所");  

  51.     }  

  52.   

  53.     @Override  

  54.     public void backToHome() {  

  55.         System.out.println(getName() + "骑自行车回到家");  

  56.     }  

  57. }  

  58. public class ModelClient {  

  59.     public static void main(String[] args) {  

  60.         Person person = new GuoPerson();  

  61.         person.summary();  

  62.         person = new ShenPerson();  

  63.         person.summary();  

  64.     }  

  65. }  


优点 
没有重复的代码了,新增一个人时也同样减少一直重复的代码 
如果在上班完加一个先吃个饭再回家,则只需要在抽象类里加上这行代码,无需改动所有Person 
缺点 
多出一个类,有时多出好几个方法 
深度思考 
模式方法模式其实就是一个抽象的过程,是最小抽象,位于抽象的最低层 
与工厂方法的区别 

总结: 
简单工厂能把具体实现包装起来,让客户端真正达到面向接口编程 
工厂方法可以在高层进行编码,让服务端的产品线真正达到面向接口编程 
抽象工厂能聚合整个产品簇,让整个服务端的多个产品线真正达到面向接口编程 
模板方法同样是在高层进行编码,也同样是面向接口编程。 
但工厂方法及抽象工厂方法着重抽象的是产品,而模板方法着重抽象的是步骤。 
而我们通常会两者一起结合起来使用。 
思考上面那个模板模式,你会发现去上班和回到家代码很相似, 
于是我们组合使用工厂模式又能去除重复代码。 
在抽象类返回一个交通工具,上下班和回到家就可以在基类编程了。 

代码如下: 

Java代码

  1. public interface Vehicle {  

  2.     String by();  

  3. }  

  4.   

  5. public class Bus implements Vehicle {  

  6.     @Override  

  7.     public String by() {  

  8.         return "坐公交车";  

  9.     }  

  10. }  

  11.   

  12. public class Bike implements Vehicle {  

  13.     @Override  

  14.     public String by() {  

  15.         return "骑自行车";  

  16.     }  

  17. }  

  18.   

  19. abstract public class AbstractPerson implements Person {  

  20.     public void summary() {  

  21.         Vehicle vehicle = getVehicle();  

  22.         System.out.println(getName() + "起床");  

  23.         System.out.println(getName() + vehicle.by() + "去上班");  

  24.         work();  

  25.         System.out.println(getName() + vehicle.by() + "回到家");  

  26.         System.out.println(getName() + "洗个澡睡觉了");  

  27.     }  

  28.     abstract public Vehicle getVehicle();  

  29.     abstract public void work();  

  30. }  

  31.   

  32. public class GuoPerson extends AbstractPerson {  

  33.     @Override  

  34.     public String getName() {  

  35.         return "郭大神";  

  36.     }  

  37.   

  38.     @Override  

  39.     public void work() {  

  40.         System.out.println(getName() + "上班到9点时上了一次厕所");  

  41.         System.out.println(getName() + "上班到10点时上了一次厕所");  

  42.         System.out.println(getName() + "上班到11点时上了一次厕所");  

  43.     }  

  44.   

  45.     @Override  

  46.     public Vehicle getVehicle() {  

  47.         return new Bus();  

  48.     }  

  49. }  

  50.   

  51. public class ShenPerson extends AbstractPerson {  

  52.     @Override  

  53.     public String getName() {  

  54.         return "盘哥";  

  55.     }  

  56.   

  57.     @Override  

  58.     public void work() {  

  59.         System.out.println(getName() + "上班到10点时上了一次厕所");  

  60.     }  

  61.   

  62.     @Override  

  63.     public Vehicle getVehicle() {  

  64.         return new Bike();  

  65.     }  

  66. }  


这样,在AbstractPerson的子类只需要返回交通工具, 就可以少掉两个方法 


↑ 上一篇文章:工厂方法模式(Factory Method Pattern)---设计模式(C++实现) 关键词:工厂方法模式,Factory,Method,Patter.. 发布日期:2016/8/25 16:09:57
↓ 下一篇文章:C++接口实现总结(转) 关键词:C++接口实现总结 发布日期:2016/8/25 16:22:41
相关目录:.NETVC&C++JAVA软件开发
我要评论
正在加载评论信息......