TheFactoryPattern(工厂模式)学习问题随着经济的全球化,一个软件可能要在全球销售。因此,我们设计的软件应该能够通过简单的配置就可以适应不同的国家。本讲所学的知识将能提供一种有助于解决此问题的方法。对象创建问题…关于new:按照面向抽象的设计原则,我们应该面向接口编程而不是面向实现编程。但是我们每次使用new时,是不是正在违背这一原则呢?我们想用接口但却必须建立一个具体类的实例Duckduck=newMallardDuck()问题…当你拥有一组相关的具体类时,你常常被迫写出类似下面的代码:Duckduck;If(picnic){duck=newMallardDuck();}elseif(hunting){duck=newDecoyDuck();}elseif(inBathTub){duck=newRubberDuck();}这样做的原因是直到运行时我们才知道需要实例化那个类。这样做的后果是如果应用要做变化或扩展,往往要修改这段代码。这使得维护困难并容易引入错误。问题在哪里?是new的问题吗?从技术上来说,new并没有任何问题。new是java最基本的部分。真正的问题在于“变化”如果对接口编程,我们可实现与许多“变化”的隔离,因为通过多态机制,你的代码对于实现接口的新类依然适用。但是使用具体类麻烦就来了,因为增加新的具体类时相应代码可能就必须修改。怎么办呢?Duckduck=newMallardDuck()上面这段代码所在的模块与MallardDuck模块形成了耦合。再回忆我们前面提出的面向对象设计的原则识别应用的变化部分,并将之与固定的部分相分离。区分变化的部分下面我们来看一个例子Pizza店披萨PizzaStore类中的一段代码-订做pizzaPublicClassPizzaStore{//…PizzaorderPizza(){Pizzapizza=newPizza();pizza.prepare();pizza.bake();pizza.cut();pizza.box();returnpizza;}//…}真希望这是一个抽象类或者接口,可惜抽象类或接口都不能被实例化而且,我们有许多种pizza,所以我们增加一些代码,来确定合适的pizza种类,然后进行制作。修改后的代码PizzaorderPizza(Stringtype){Pizzapizza;if(type.equals(“cheese”)){pizza=newCheesePizza();}elseif(type.equals(“greek”)){pizza=newGreekPizza();}elseif(type.equals(“pepperoni”)){pizza=newPepperoniPizza();}pizza.prepare();pizza.bake();pizza.cut();pizza.box();returnpizza;}根据接受的类型,创建相应的pizza实例,并赋值给实例变量。(注意:各种pizza实现接口Pizza)传递pizza的类型给方法orderPizza每一种pizza子类型都知道其制作方法由于市场竞争。。。其他pizza店推出了新产品,我们也得增加!例如VeggiePizza。GreekPizza最近不受欢迎,把它从菜单中取消。于是。。。改!改!改!PizzaorderPizza(Stringtype){Pizzapizza;if(type.equals(“cheese”)){pizza=newCheesePizza();}elseif(type.equals(“greek”)){pizza=newGreekPizza();}elseif(type.equals(“pepperoni”)){pizza=newPepperoniPizza();}elseif(type.equals(“veggie”)){pizza=newVeggiePizza();}pizza.prepare();pizza.bake();pizza.cut();pizza.box();returnpizza;}变与不变变与不变PizzaorderPizza(Stringtype){Pizzapizza;if(type.equals(“cheese”)){pizza=newCheesePizza();}elseif(type.equals(“greek”)){pizza=newGreekPizza();}elseif(type.equals(“pepperoni”)){pizza=newPepperoniPizza();}elseif(type.equals(“veggie”)){pizza=newVeggiePizza();}pizza.prepare();pizza.bake();pizza.cut();pizza.box();returnpizza;}这是变化的部分。随着Pizza菜单的变化,这部分要跟着不断地变。这部分是不变的部分。分离PizzaorderPizza(Stringtype){Pizzapizza;if(type.equals(“cheese”)){pizza=newCheesePizza();}elseif(type.equals(“greek”)){pizza=newGreekPizza();}elseif(type.equals(“pepperoni”)){pizza=newPepperoniPizza();}elseif(type.equals(“veggie”)){pizza=newVeggiePizza();}pizza.prepare();pizza.bake();pizza.cut();pizza.box();returnpizza;}把这部分封装在一个只管如何创建pizza的对象中if(type.equals(“cheese”)){pizza=newCheesePizza();}elseif(type.equals(“greek”)){pizza=newGreekPizza();}elseif(type.equals(“pepperoni”)){pizza=newPepperoniPizza();}elseif(type.equals(“veggie”)){pizza=newVeggiePizza();}将创建pizza对象的代码从orderPizza方法中分离出去专管制作pizza的对象我们将专管制作pizza的对象叫做Pizza工厂PizzaorderPizza(Stringtype){Pizzapizza;pizza.prepare();pizza.bake();pizza.cut();pizza.box();returnpizza;}PizzaFactory要求制作pizza这样,orderPizza方法就成为PizaFactory的客户。Pizza工厂---SimplePizzaFactorypublicclassSimplePizzaFactory{publicPizzacreatePizza(Stringtype){Pizzapizza=null;if(type.equals(“cheese”)){pizza=newCheesePizza();}elseif(type.equals(“pepperoni”)){pizza=newPepperoniPizza();}elseif(type.equals(“veggie”)){pizza=newVeggiePizza();}returnpizza;}}Pizza工厂中定义了“生产”pizza的方法。所有客户都可以用它来实例化新的pizza对象这部分代码就是从orderPizza()方法中抽出来的。和原来的方法一样,也是通过参数确定pizza的种类。思考一下!这看来好像我们只是把问题从一个对象推给了另一个对象!这样做有什么好处呢?可以解除客户代码(PizzaStore)与具体Pizza的耦合。SimplePizzaFactory可以有许多个客户,这样,当实现改变时我们只需要修改SimplePizzaFactory,而不需修改众多的客户。提高了聚合度,PizzaStore的职责是使用pizza对象,SimplePizzaFactory的职责是决定创建什么样的pizza对象。重写PizzaStore类publicclassPizzaStore{SimplePizzaFactoryfactory;publicPizzaStore(SimplePizzaFactoryfactory){this.factory=factory;}publicPizzaorderPizza(Stringtype){Pizzapizza;pizza=factory.createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();returnpizza;}//othermethodshere}简单工厂模式PizzaStoreorderPizza()SimplePizzaFactorycreatePizza()PizzaPrepare()Bake()Cut()Box()CheesePizzaVeggiePizzaClamPizzaPepperoniPizzaPizza可以是一个抽象类,也可以是一个接口。PizzaStore1orderPizza()框架框架的对外接口简单工厂模式ClientorderProduct()SimpleFactorycreateProduct()AbstractProductmethodOfProduct()Product1Product2Product3Productn有人认为这还不是一个真正的模式,只是一种程序设计的习惯。授权pizza店我们的pizza店非常成功,许多人都想开设我们的授权加盟店。但是,不同地区的加盟pizza店可能希望供应不同口味的pizza。怎么解决这个问题呢?解决方法之一:建立不同的工厂建立不同的工厂:如NYPizzaFactory、ChicagoPizzaFactory、CaliforniaPizzaFactory,在PizzaStore中包含相应工厂的实例。其代码类似于://该pizza店提供纽约风味的pizzaNYPizzaFactorynyFactory=newNYPizzaFactory();//建立一个生产纽约风味pizza的工厂PizzaStorenyStore=newPizzaStore(nyFactory);//建立一个pizza店,引用纽约风味pizza的工厂nyStore.orderPizza(“Veggie”);//生产的是纽约风味的pizza//该pizza店提供芝加哥风味的pizzaChicagoPizzaFactorychicagoFactory=newChicagoPizzaFactory();PizzaStorechicagoStore=newPizzaStore(chicagoFactory);chicagoStore.orderPizza(“Veggie”);抽象工厂模式这么多工厂,可以再增加抽象层让我们一起来设计…AbstractFactorycreateProduct()ConcreteFactorycreateProduct()另一种解决方法-工厂方法模式思路:改写的PizzaStore,将createPizza()方法放回到PizzaStore,但是声明为抽象方法,然后,为每一种地方风味创建一个PizzaStore的子类。改造后的PizzaStore的代码publicabstractclassPizzaStore{publicPizzaorderPizza(Stringtype){Pizzapizza=createPizza(type);pizza.prepa