`
xiao_yi
  • 浏览: 406121 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

设计模式入门学习之工厂模式

阅读更多
  当看到"new",就会想到"具体","new"有什么不对劲的?
在技术上,new没有错,毕竟这是java的基础部分.针对接口编程,可以隔离掉以后系统可能发生的一大堆改变.为什么呢?如果代码是针对接口而写,你们通过多态,它可以与任何新类实现该接口.但是,当代码使用大量的具体类时,等于是自找麻烦,因为一但加入新的具体类就必须改变代码,也就是说你的代码并非"对修改关闭".别忘了,我们的第一个原则用来处理改变,"找出会变化的方面,把它们从不变的部分分离出来".
假设你有个披萨店,你的代码可能这么写:
Java代码 复制代码
  1. pizza orderPizza(){   
  2.     Pizza piz = new Pizza();   
  3.     //为了让系统有弹性,我们很希望这是一个抽象类或接口,但如果这样,这些类或接口就无法直接实例化   
  4.     piz.prepare();   
  5.     piz.bake();   
  6.     piz.cut();   
  7.     piz.box();   
  8.     return piz;   
  9. }  

 

但是你需要更多的披萨类型,所以必须增加一些代码,来决定适合的披萨类型,然后再制造这个披萨:

Java代码 复制代码
  1. pizza orderPizza(String type){   
  2.     //现在把披萨类型传入orderPizza   
  3.     Pizza piz;   
  4.     //根据披萨的类型,实例化正确的具体类,注意这里的任何披萨都必须实现Pizza接口   
  5.     if(type.equals("cheese")){   
  6.         piz = new CheesePizza();   
  7.     }else if(type.equals("greek")){   
  8.         piz = new GreekPizza();   
  9.     }   
  10.     //某一天你为了赶上竞争者,你加入了一些流行风味的披萨,greek披萨卖的不好,你要从菜单去掉,随着时间的过去,这里就必须一改再改   
  11.     else if(type.equals("clam")){   
  12.         piz = new ClamPizza();   
  13.     }   
  14.     else if(type.equals("veggie")){   
  15.         piz = new VeggaePizza();   
  16.     }   
  17.     //一旦我们有了一个披萨,需要做一些准备,然后烘烤.切片.装盒,这里是我们不想改变的地方   
  18.     piz.prepare();   
  19.     piz.bake();   
  20.     piz.cut();   
  21.     piz.box();   
  22.     return piz;   
  23. }  

现在我们知道哪些会改变哪些不会改变,该是使用封装的时候了,现在我们把创建对象的代码抽离,建立一个简单披萨工厂,这个工厂只管如何创建披萨:

Java代码 复制代码
  1. public class SimplePizzaFactory {   
  2.     //内定一个createPizza()方法,所有客户通过这个方法来实例化新对象   
  3.     public Pizza createPizza(String type) {   
  4.         Pizza pizza = null;   
  5.         //移植过来的代码,基本没什么变动   
  6.         if (type.equals("cheese")) {   
  7.             pizza = new CheesePizza();   
  8.         } else if (type.equals("pepperoni")) {   
  9.             pizza = new PepperoniPizza();   
  10.         } else if (type.equals("clam")) {   
  11.             pizza = new ClamPizza();   
  12.         } else if (type.equals("veggie")) {   
  13.             pizza = new VeggiePizza();   
  14.         }   
  15.         return pizza;   
  16.     }   
  17. }  

 

这么做有什么好处?似乎只是把问题搬到另一个对象罢了,问题依然存在.
别忘了,SimplePizzaFactory可以有很多客户,虽然目前只看到orderPizza()方法是它的客户,然而可能还有其他的客户.所以把创建披萨的代码包装进一个类,当以后实现改变时,只需修改这个类即可.别忘了,我们正要把具体实例化过程从客户的代码中删除.
修改客户代码,重做PizzaStore类:

Java代码 复制代码
  1. public class PizzaStore {   
  2.     //加一个SimplePizzaFactory的引用   
  3.     SimplePizzaFactory factory;   
  4.     public PizzaStore(SimplePizzaFactory factory) {    
  5.         this.factory = factory;   
  6.     }   
  7.     public Pizza orderPizza(String type) {   
  8.         Pizza pizza;   
  9.         //而orderPizza()方法通过简单传入订单类型来使用工厂创建披萨,   
  10.         //请注意,我们把new操作符替换成工厂对象的创建方法,这里不在使用具体实例化   
  11.         pizza = factory.createPizza(type);   
  12.     
  13.         pizza.prepare();   
  14.         pizza.bake();   
  15.         pizza.cut();   
  16.         pizza.box();   
  17.         return pizza;   
  18.     }   
  19.     //...other methon   
  20. }  

简单工厂其实不是一个设计模式,反而比较像是一种编程习惯,接下来继续用披萨店来讲述工厂方法模式.
披萨店经营有成,击败了竞争者,现在大家都希望来加盟你的披萨店,身为经营者,你希望确保加盟店的营运质量,希望这些店都使用你那些经过时间考验的代码.但是区域的差异呢?每家加盟店都可能想要提供不同风味的披萨,比方说纽约.芝加哥.加州,这就受到了开店地点及该地区口味的影响.
如果利用SimplePizzaFactory,写出3种不同的工厂,分别是NYPizzaFactory,ChicagoPizzaFactory,CaliforniaPizzaFactory,那么各个加盟店都有合适的工厂可以使用,这是一种做法:
NYPizzaFactory nyFactory = new NYPizzaFactory();//这里创建的工厂是制造纽约风味的披萨
PizzaStore nyStore = new PizzaStore(nyFactory);//然后建立一个披萨店,将纽约工厂的引用作为参数
nyStore.orderPizza("Veggie");   //制造披萨,会得到纽约风味的披萨
在推广SimplePizzaFactory时,你发现加盟店的确采用你的工厂创建披萨,但是他们自创流程:烘烤的做法有些差异.不要切片.使用其他厂商的盒子.怎么让你的质量多一些质量控制多些弹性呢?
我们再来修改一些披萨店,先声明一个工厂方法:

Java代码 复制代码
  1. //现在PizzaStore是抽象的,每个子类都会覆盖createPizza方法,同时使用PizzaStore定义的orderPizza方法,   
  2. //甚至可以把orderPizza定义为tinal,以防止被之类覆盖   
  3. public abstract class PizzaStore {   
  4.     /**  
  5.     *现在把工厂对象移到这个方法中,工厂方法现在是抽象的,所以依赖子类来处理对象的创建  
  6.     *工厂方法必须返回一个产品,超类中定义的方法,通常使用到工厂方法的返回值  
  7.     *工厂方法将客户(如orderPizza)和实际创建具体产品的代码分割开来  
  8.     */  
  9.     abstract Pizza createPizza(String type);   
  10.     
  11.     public Pizza orderPizza(String type) {   
  12.         //现在createPizza()方法从工厂对象中移回PizzaStore   
  13.         Pizza pizza = createPizza(type);   
  14.         pizza.prepare();   
  15.         pizza.bake();   
  16.         pizza.cut();   
  17.         pizza.box();   
  18.         return pizza;   
  19.     }   
  20. }  

 

好了,让我们把纽约风味的加盟店开起来吧:

Java代码 复制代码
  1. //createPizza()返回一个Pizza对象,由子类全权负责该实例化哪一个具体Pizza   
  2. public class NYPizzaStore extends PizzaStore {   
  3.     //必须实现的createPizza方法   
  4.     Pizza createPizza(String item) {   
  5.         if (item.equals("cheese")) {   
  6.             return new NYStyleCheesePizza();   
  7.         } else if (item.equals("veggie")) {   
  8.             return new NYStyleVeggiePizza();   
  9.         } else if (item.equals("clam")) {   
  10.             return new NYStyleClamPizza();   
  11.         } else if (item.equals("pepperoni")) {   
  12.             return new NYStylePepperoniPizza();   
  13.         } else return null;   
  14.     }   
  15. }  

 

实现一下披萨本身,没披萨开什么加盟店呢:

Java代码 复制代码
  1. //从一个抽象披萨类开始,所有的具体披萨都必须派生自这个类   
  2. public abstract class Pizza {   
  3.     String name;    //每个披萨都有名称,面团类型,一套佐料   
  4.     String dough;   
  5.     String sauce;   
  6.     ArrayList toppings = new ArrayList();   
  7.     void prepare() {   
  8.         System.out.println("Preparing " + name);   
  9.         System.out.println("Tossing dough...");   
  10.         System.out.println("Adding sauce...");   
  11.         System.out.println("Adding toppings: ");   
  12.         //准备工作需要以特定的顺序进行   
  13.         for (int i = 0; i < toppings.size(); i++) {   
  14.             System.out.println("   " + toppings.get(i));   
  15.         }   
  16.     }   
  17.     void bake() {}   
  18.     void cut() {}   
  19.     void box() {}   
  20.     public String getName() {return name;}   
  21.     public String toString() {   
  22.         StringBuffer display = new StringBuffer();   
  23.         display.append("---- " + name + " ----\n");   
  24.         display.append(dough + "\n");   
  25.         display.append(sauce + "\n");   
  26.         for (int i = 0; i < toppings.size(); i++) {   
  27.             display.append((String )toppings.get(i) + "\n");   
  28.         }   
  29.         return display.toString();   
  30.     }   
  31. }  

 

现在我们来定义纽约和芝加哥风味的具体子类,并吃些披萨怎么样:

Java代码 复制代码
  1. public class NYStyleCheesePizza extends Pizza {   
  2.     public NYStyleCheesePizza() {    
  3.         name = "NY Style Sauce and Cheese Pizza";   
  4.         dough = "Thin Crust Dough";   
  5.         sauce = "Marinara Sauce";   
  6.         toppings.add("Grated Reggiano Cheese");   
  7.     }   
  8. }   
  9. public class ChicagoStyleCheesePizza extends Pizza {   
  10.     public ChicagoStyleCheesePizza() {    
  11.         name = "Chicago Style Deep Dish Cheese Pizza";   
  12.         dough = "Extra Thick Crust Dough";   
  13.         sauce = "Plum Tomato Sauce";   
  14.         toppings.add("Shredded Mozzarella Cheese");   
  15.     }   
  16.     //这个芝加哥风味披萨覆盖cut()方法,将披萨切成正方形   
  17.     void cut() {   
  18.         System.out.println("Cutting the pizza into square slices");   
  19.     }   
  20. }   
  21. public class PizzaTestDrive {   
  22.     public static void main(String[] args) {   
  23.         //建立2个不同的店   
  24.         PizzaStore nyStore = new NYPizzaStore();   
  25.         PizzaStore chicagoStore = new ChicagoPizzaStore();   
  26.         //下订单   
  27.         Pizza pizza = nyStore.orderPizza("cheese");   
  28.         System.out.println("Ethan ordered a " + pizza.getName() + "\n");   
  29.         pizza = chicagoStore.orderPizza("cheese");   
  30.         System.out.println("Joel ordered a " + pizza.getName() + "\n");   
  31.   
  32.     }   
  33. }  

 

认识工厂方法模式的时刻终于到了,工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪个.工厂方法让类把实例化推迟到子类
分享到:
评论

相关推荐

    设计模式之美—学习笔记

    设计模式是软件工程中的一种最佳实践,它是在特定上下文中解决常见问题的经验总结。这些模式在不同的场景下被反复验证并被广泛接受,为开发者提供了一种标准的、可复用的解决方案。在这个“设计模式之美”的学习笔记...

    Java设计模式入门闲谈

    ### Java设计模式入门详解 #### 一、设计模式概述 设计模式是软件工程领域中一种通用的解决方案,它描述了在特定情况下解决常见问题的方法。《设计模式:可复用面向对象软件的基础》(Design Patterns: Elements ...

    设计模式入门指导

    在探讨设计模式的入门知识之前,我们需要对面向对象(Object-Oriented,OO)和面向过程(Procedure-Oriented)...在学习过程中,理解其背后的面向对象原则,了解不同设计模式的特点和适用场景,是入门设计模式的关键。

    设计模式解析.pdf

    #### 描述解析:设计模式的入门与精通之路 描述中提到设计模式和面向对象编程,强调了它们对于软件设计师和开发者的重要性。这表明书籍将从基础出发,逐步深入,不仅教授设计模式的基础知识,还将引导读者理解设计...

    CC++与设计模式基础课程_讲义

    在《CC++与设计模式基础课程》中,我们可以看到设计模式的学习被划分为三个主要类别:创建型、结构型和行为型模式。这些模式分别对应了对象创建、对象组合和对象交互的不同场景。 创建型模式有五种,包括: 1. 工厂...

    GOF设计模式中英文+设计模式精解中英文

    GOF(Gang of Four)设计模式,由Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides四位专家在他们的著作《设计模式:可复用面向对象软件的基础》中提出,被誉为设计模式的经典之作。本资源包含了GOF设计...

    设计模式基础学习 各种软件设计模式

    ### 设计模式基础学习——构建面向对象软件的艺术 在软件工程领域,设计模式是一种用于解决常见问题的模板或指南,特别是在面向对象编程中。本文旨在深入探讨设计模式的基础概念及其在软件开发中的重要性,根据给定...

    CC++与设计模式基础课程-讲义

    本课程旨在为初学者提供一个系统化的学习路径,帮助他们快速入门CC++和设计模式的世界。本课程涵盖了设计模式的基础知识,包括设计模式的定义、分类、应用场景等,同时也提供了一些实战应用的经验和建议。 设计模式...

    《设计模式:可复用面向对象软件的基础》学习并理解 23 种设计模式

    ### 设计模式基础及其重要性 #### 设计模式概述 设计模式是一种被广泛采用的、经过验证的解决方案,用于解决软件开发过程中常见的设计问题。它不仅帮助开发者编写可复用的代码,还促进了团队成员之间的有效沟通。...

    最新设计模式入门手册 chm

    《最新设计模式入门手册》是一本专为软件开发者编写的指南,旨在帮助初学者理解和掌握设计模式的基础知识。设计模式是软件工程中的一个重要概念,它代表了在特定上下文中解决问题的常见方法,经过时间的检验,被证明...

    设计模式:可复用面向对象软件的基础(非扫描版+高清)

    《设计模式:可复用面向对象软件的基础》是一本经典的软件工程著作,它详细阐述了在面向对象编程中,如何通过使用预定义的解决方案模板来解决常见问题,从而提高代码的可读性、可维护性和复用性。设计模式是经验丰富...

    设计模式学习总结.doc

    文档中提到了《设计模式:可复用的面向对象软件的基础》这本书,这是设计模式领域的经典之作,书中详细介绍了23种设计模式,包括单例模式、工厂模式、观察者模式等。 在应用设计模式时,文档强调了理解模式的意图和...

    Java设计模式之禅

    《Java设计模式之禅》是一本深入浅出讲解设计模式的书籍,书中不仅包含23种经典设计模式的案例,还详细介绍了设计模式背后的思想和原则,适合初学者以及对设计模式有一定了解的程序员阅读。本书旨在帮助读者理解如何...

    (转)网上不错的设计模式入门

    设计模式是软件工程中的一种重要概念,它代表了在特定情境下解决问题的...同时,深入学习经典的书籍,如《设计模式:可复用面向对象软件的基础》(通常被称为“大头书”),可以帮助开发者更全面地掌握设计模式的精髓。

    工厂设计模式代码

    工厂设计模式是软件工程中广泛使用的一种创建型设计模式,它的主要目的是为了隔离对象的创建过程,使得客户端代码不直接创建对象,而是通过一个专门的工厂类来负责对象的实例化。这种模式使得系统在面对产品扩展时...

    设计模式之工厂系列

    在软件开发领域,设计模式是一种经过...学习和理解工厂系列设计模式,对于提高代码的可读性、可维护性和复用性具有重要意义。在实际项目中,合理运用这些模式能有效降低系统的耦合度,提高系统的可扩展性和可维护性。

    设计模式全套学习ppt

    ### 设计模式全套学习PPT知识点总结 #### 一、设计模式概述 设计模式是在软件设计过程中遇到的常见问题的解决方案。这些模式并不是具体的代码,而是一些指导思想,可以帮助开发者更好地解决特定类型的问题,提高...

    设计模式:可复用面向对象软件的基础.zip

    设计模式是软件工程中的一种重要概念,它代表了在特定情境下解决常见问题的最佳实践。这些模式经过时间的考验,被广泛应用于各种面向对象的软件开发中,以提高代码的可读性、可维护性和可复用性。本教程旨在深入讲解...

Global site tag (gtag.js) - Google Analytics