当前位置: 代码迷 >> 综合 >> HeadFirst(四)Factory 工厂设计模式
  详细解决方案

HeadFirst(四)Factory 工厂设计模式

热度:11   发布时间:2024-01-10 04:43:51.0

 

当有一堆对象等着被实例化,究竟实现哪个类,需要在运行时由一些条件来决定!

 

如果代码是针对接口编写的,那么通过多态的特性,它就能与任何新的实现类进行绑定,从而实现扩展!

 

找出会变化的地方,把它们从不变的部分分离出来,单独进行设计!

 

工厂方法研究:

如何将实例化具体类的代码从应用中抽离,或者封装起来,使它们不会干扰其它部分。

 

每当需求发生变化或者有新的需求时,你必须对原来的代码进行修改才能完成对需求的实现,如果是这样的话,你应该意识到:你的系统在设计上存在严重问题!!!

对修改没关闭,对扩展没开放,3个字--->烂透了!

 

 

将创建对象的代码封装到一个对象中,这个对象就叫做工厂!


 

工厂模式的几种变体(所有的工厂模式都是用来封装对象的创建)

 

静态工厂

定义外部类Factory,并提供静态方法调用,返回对象

 

简单工厂

定义外部类Factory,使用者需要组合Factory到类中,再委托Factory对象去调用自己的方法返回对象

 

工厂方法

父类定义一个抽象的方法(该方法在框架中被调用),让子类去重写并决定返回对象的类型

工厂方法模式

 定义了一个创建对象的接口(实为一个抽象方法),但由子类决定要实例化的类是哪一个。

工厂方法让类的实例化推迟到子类中进行。

 

抽象工厂

通过接口定义一个抽象的顶层工厂,子类为一系列不同的具体工厂

通过抽象工厂中定义好的接口,创建一个产品家族。

 

 

所有的工厂都是用来封装对象的创建

 

简单工厂,虽然不是真正的设计模式,但仍不失为一个简单的方法,可以将客户程序从具体类中解耦

 

工厂方法使用继承,把对象的创建委托给子类,子类实现工厂方法来创建对象

 

抽象工厂使用对象组合,对象的创建被实现在工厂接口所暴露出来的方法中

 

所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合

 

工厂方法允许类将实例化延迟到子类中进行

 

抽象工厂创建相关的对象家族,而不需要依赖它们的具体类

 

依赖倒置原则,指导我们避免依赖具体类型,而要尽量依赖抽象

 

=======================================================================

 

静态工厂(比较常用,因为简单)

好处:不需要创建对象

缺点:不能通过继承来改变方法的行为,几乎不能扩展(已将静态调用写死在代码里)

 

 

 

package staticfactory;/*** 各种Pizza的基类**/
public abstract class Pizza {public void makePizza() {this.prepare();this.bake();this.cut();this.box();}abstract void prepare();abstract void bake();abstract void cut();abstract void box();
}

 

package staticfactory;public class CheesePizza extends Pizza {@Overridevoid prepare() {System.out.println("prepare CheesePizza");}@Overridevoid bake() {System.out.println("bake CheesePizza");}@Overridevoid cut() {System.out.println("cut CheesePizza");}@Overridevoid box() {System.out.println("box CheesePizza");}}

 

package staticfactory;public class ClamPizza extends Pizza {@Overridevoid prepare() {System.out.println("prepare ClamPizza");}@Overridevoid bake() {System.out.println("bake ClamPizza");}@Overridevoid cut() {System.out.println("cut ClamPizza");}@Overridevoid box() {System.out.println("box ClamPizza");}}

 

package staticfactory;public class VeggiePizza extends Pizza {@Overridevoid prepare() {System.out.println("prepare VeggiePizza");}@Overridevoid bake() {System.out.println("bake VeggiePizza");}@Overridevoid cut() {System.out.println("cut VeggiePizza");}@Overridevoid box() {System.out.println("box VeggiePizza");}}

 

静态工厂(对外提供静态方法进行访问)

package staticfactory;public class StaticPizzaFactory {/*** 负责创建各种类型Pizza的工厂,且为static的!*/public static Pizza createPizza(String pizzaName) {Pizza pizza = null;if(pizzaName==null || "".equals(pizzaName.trim())) {throw new RuntimeException("Please specify your pizza!");}try {Class<?> clazz = Class.forName(pizzaName);pizza = (Pizza) clazz.newInstance(); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {e.printStackTrace();throw new RuntimeException(e);}return pizza;}
}

 

Pizza店

package staticfactory;public class PizzaStore {public Pizza orderPizza(String cheeseName) {Pizza pizza;pizza = StaticPizzaFactory.createPizza(cheeseName);pizza.makePizza();return pizza;}}

 

测试

package test;import staticfactory.PizzaStore;public class PizzaTest {public static void main(String[] args) {PizzaStore store = new PizzaStore();orderPizza(store);}private static void orderPizza(PizzaStore store) {store.orderPizza("staticfactory.CheesePizza");store.orderPizza("staticfactory.ClamPizza");store.orderPizza("staticfactory.VeggiePizza");}
}

 

 

 

 

=======================================================================

 

简单工厂

 

组合工厂到类中

package simplefactory;public class PizzaStore {//与工厂组合SimplePizzaFactory factory;public PizzaStore(SimplePizzaFactory simplePizzaFactory) {factory = simplePizzaFactory;//实例化工厂}public Pizza orderPizza(String cheeseName) {Pizza pizza;pizza = factory.createPizza(cheeseName);//委托工厂创建Pizzapizza.makePizza();return pizza;}}

 

简单工厂(非静态),需要由对象来调用工厂中的方法

package simplefactory;public class SimplePizzaFactory {/*** 负责创建各种类型Pizza的工厂*/public Pizza createPizza(String pizzaName) {Pizza pizza = null;if(pizzaName==null || "".equals(pizzaName.trim())) {throw new RuntimeException("Please specify your pizza!");}try {Class<?> clazz = Class.forName(pizzaName);pizza = (Pizza) clazz.newInstance(); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {e.printStackTrace();throw new RuntimeException(e);}return pizza;}
}

 

测试

package test;import simplefactory.SimplePizzaFactory;
import simplefactory.PizzaStore;public class PizzaTest {public static void main(String[] args) {//创建工厂实例对象SimplePizzaFactory factory = new SimplePizzaFactory();//将工厂对象传入PizzaStore的构造方法中PizzaStore store = new PizzaStore(factory);orderPizza(store);}private static void orderPizza(PizzaStore store) {store.orderPizza("simplefactory.CheesePizza");store.orderPizza("simplefactory.ClamPizza");store.orderPizza("simplefactory.VeggiePizza");}
}

 

 

 

 

=======================================================================

 

工厂方法

 

基类不知道运行时会是哪一个子类在运行---> 解耦, 基类只知道子类可以具备某些行为

具体的对象都是在运行时通过多态实现动态绑定的!

编程时只面对接口,而不是实现类,让代码更具弹性,应对未来的扩展!

 



 

 

简单工厂与工厂方法的区别:

 

简单工厂,是一个被PizzaStore使用的对象,简单工厂作为外部一个类被组合到PizzaStore中;

简单工厂,把全部的事情在一个地方都处理完了。

 

工厂方法,有一个抽象方法createPizza(),由PizzaStore的子类自行负责createPizza()的行为;

工厂方法,创建了一个框架(框架依赖工厂方法创建具体类),让子类决定要如何实现。

 

设计原则

依赖抽象,不要依赖具体类

不能让高层组件依赖于底层组件,而且,不管高层或底层组件,两者都应该依赖于抽象

简单点说,就是要面向抽象编程

 

变量不可以持有具体类的引用

如果使用new,就会持有具体类的引用。

你可以改用工厂来避开这样的做法。

不要让类派生自具体类

如果派生自具体类,你就依赖具体类。

请派生自一个抽象(接口或抽象类)。

不要覆盖基类中已经实现的方法

如果覆盖基类已经实现的方法,那么你的基类就不是一个真正适合被继承的抽象。

基类中已实现的方法,应该由所有子类共享。

 

尽量达到上述要求,而不是随时都要遵守,根据实际情况考量!

 

 

Pizza 抽象类

 

package factorymethode;import java.util.ArrayList;public abstract class Pizza {String name;//名称String dough;//面团String sauce;//果酱ArrayList<String> toppings = new ArrayList<String>();//若干佐料public void prepare(){System.out.println("firsrt: Prepare " + name);System.out.println("second: Tossing dough...");System.out.println("third: Add sauce...");System.out.println("fouth: Add toppings: ");for(String topping : toppings) {System.out.print("    " + topping);}System.out.println();}public void bake() {System.out.println("Bake for 25 minutes");}public void cut() {System.out.println("Cutting the pizza into diagonal slices");}public void box() {System.out.println("Place pizza in official PizzaStore box");}public String getName() {return name;}
}
 

 

 

具体的Pizza-NYStyleCheesePizza

 

package factorymethode;public class NYStyleCheesePizza extends Pizza {public NYStyleCheesePizza() {name = "NY Style Sauce and Cheese Pizza";dough = "Thin Crust Dough";sauce = "Marinara Sauce";toppings.add("Grated Reggiano Cheese");}}
 

 

具体的Pizza---ChicagoStyleCheesePizza

 

package factorymethode;public class ChicagoStyleCheesePizza extends Pizza {public ChicagoStyleCheesePizza() {name = "Chicago Style Deep Dish Cheese Pizza";dough = "Extra Thick Crust Dough";sauce = "Plum Tomato Sauce";toppings.add("Shredded Mozzarella Cheese");}/*** 覆盖父类的方法*/@Overridepublic void cut() {System.out.println("Cutting the pizza into square slices");}}
 

 

PizzaStore抽象类

 

package factorymethod.pizza;import factorymethode.Pizza;public abstract class PizzaStore {/*** 订购Pizza的流程是久经考验的,用final修饰,不允许子类进行改变!* * 提供了一般的框架(定义好流程),以便创建Pizza* 依赖抽象工厂方法创建具体的子类,并创建出实际的Pizza*/final public Pizza orderPizza(String type) {//依赖与抽象Pizza pizza;//超类型/父类/接口//调用抽象工厂方法,在运行时由具体的子类来返回实例对象pizza = createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}/*** 工厂移到这里了,不再单独定义,而是用一个方法(抽象工厂方法)完成对象的创建* 具体对象由子类根据各自的需求进行返回---解耦* * 参数化工厂方法,参数错误将发生运行时异常* 解决办法:使用枚举类型作为参数,在编译期对参数进行检查* @return 具体的子类对象*/abstract Pizza createPizza(String type);
}
 

 

具体的PizzaStore---NYPizzaStore

 

package factorymethod.pizza;import factorymethode.NYStyleCheesePizza;
import factorymethode.Pizza;public class NYPizzaStore extends PizzaStore {/*** 子类对抽象方法进行实现* 返回自己需要的对象*/@OverridePizza createPizza(String type) {if(type.equals("cheese")) {return new NYStyleCheesePizza();}return null;}}
 
具体的PizzaStore---ChicagoPizzaStore
package factorymethod.pizza;import factorymethode.ChicagoStyleCheesePizza;
import factorymethode.Pizza;public class ChicagoPizzaStore extends PizzaStore {/*** 子类对抽象方法进行实现* 返回自己需要的对象*/@OverridePizza createPizza(String type) {if(type.equals("cheese")) {return new ChicagoStyleCheesePizza();}return null;}}
 
测试
package test;import factorymethod.pizza.ChicagoPizzaStore;
import factorymethod.pizza.NYPizzaStore;
import factorymethod.pizza.PizzaStore;
import factorymethode.ChicagoStyleCheesePizza;public class PizzaTest {public static void main(String[] args) {orderNYStylePizza();System.out.println("==========================");orderChicagoStylePizza();}private static void orderChicagoStylePizza() {PizzaStore store = new ChicagoPizzaStore();store.orderPizza("cheese");}private static void orderNYStylePizza() {PizzaStore store = new NYPizzaStore();store.orderPizza("cheese");}}
 

 

 

 

=======================================================================

 

抽象工厂

 提供一个接口(抽象方法),用于创建相关或依赖对象的家族(A1产品,A2产品...)

 抽象工厂用来完成一组产品对象的创建

 

抽象工厂实际内部使用了工厂方法模式

factory1:创建A产品A1,B产品B1

factory2:创建A产品A2,B产品B2

...

上面每一个factory,都是一个工厂方法模式的应用

这些不同的factory,又有自己的基类工厂,abstractFactory

在Client中,只面向abstractFactory,通过abstractFactory进行调用即可。

如此组合起来,就形成了抽象工厂模式

Client(PizzaStore超类)中提供一个抽象方法,这个抽象方法在子类中实现时,将调用上面的abstractFactory进行产品A,B 的创建

 

基类中组合抽象的基类

在运行时通过多态特性,实现不同子类对象的动态绑定!

 



 



 

 

 

工厂方法与抽象工厂的比较

 

工厂方法:

通过继承父类,实现父类的抽象方法并返回具体的对象

如,NYPizzaStore继承PizzaStore,通过实现createPizza()返回NYStyleCheesePizza

 

抽象工厂:

通过对象间的组合,通过被组合的对象去调用子类的方法,完成所需对象的创建

如,NYStyleCheesePizza中,通过与PizzaIngredientFactory进行组合,在覆盖父类的抽象方法prepare()时,调用PizzaIngredientFactory对一组原料对象进行创建

 

可以把一组相关的产品集中起来进行创建;

缺点:如果需要扩展新的产品,就必须改变接口;

 

 

抽象工厂模式应用示例

不同地区的PizzaStore需要使用不同的原料来制作Pizza

 

原料---接口

public interface Cheese {}

 

public interface Clam {}

 

public interface Dough {}

 

public interface Pepperoni {}

 

public interface Sauce {}

 

public interface Veggies {}

 

具体原料---纽约PizzaStore使用的原料,芝加哥PizzaStore使用的原料

public class ChicagoCheese implements Cheese{}
 
public class NYCheese implements Cheese{}
 
public class ChicagoClam implements Clam{}
 
public class NYClam implements Clam{}
 
public class ChicagoDough implements Dough{}
 
public class NYDough implements Dough{}
 ....其它原料类似,不再列出
抽象工厂---定义一组方法对Pizza原料进行创建
package abstractfactory;import abstractfactory.ingredient.Cheese;
import abstractfactory.ingredient.Clam;
import abstractfactory.ingredient.Dough;
import abstractfactory.ingredient.Pepperoni;
import abstractfactory.ingredient.Sauce;
import abstractfactory.ingredient.Veggies;/*** 定义一组产品的创建 */
public interface PizzaIngredientFactory {public abstract Dough createDough();public abstract Sauce createSauce();public abstract Cheese createCheese();public abstract Veggies[] createVeggies();public abstract Pepperoni createPepperoni();public abstract Clam createClam();
}
 
具体工厂---NYPizzaIngredientFactory
package abstractfactory;import abstractfactory.ingredient.Cheese;
import abstractfactory.ingredient.Clam;
import abstractfactory.ingredient.Dough;
import abstractfactory.ingredient.Pepperoni;
import abstractfactory.ingredient.Sauce;
import abstractfactory.ingredient.Veggies;
import abstractfactory.ingredient.impl.NYCheese;
import abstractfactory.ingredient.impl.NYClam;
import abstractfactory.ingredient.impl.NYDough;
import abstractfactory.ingredient.impl.NYPepperoni;
import abstractfactory.ingredient.impl.NYSauce;
import abstractfactory.ingredient.impl.VeggieGarlic;
import abstractfactory.ingredient.impl.VeggieOnion;/*** 纽约原料工厂**/
public class NYPizzaIngredientFactory implements PizzaIngredientFactory{@Overridepublic Dough createDough() {return new NYDough();}@Overridepublic Sauce createSauce() {return new NYSauce();}@Overridepublic Cheese createCheese() {return new NYCheese();}@Overridepublic Veggies[] createVeggies() {Veggies[] veggies = {new VeggieGarlic(), new VeggieOnion()};return veggies;}@Overridepublic Pepperoni createPepperoni() {return new NYPepperoni();}@Overridepublic Clam createClam() {return new NYClam();}}
 
具体工厂---ChicagoPizzaIngredientFactory
package abstractfactory;import abstractfactory.ingredient.Cheese;
import abstractfactory.ingredient.Clam;
import abstractfactory.ingredient.Dough;
import abstractfactory.ingredient.Pepperoni;
import abstractfactory.ingredient.Sauce;
import abstractfactory.ingredient.Veggies;
import abstractfactory.ingredient.impl.ChicagoCheese;
import abstractfactory.ingredient.impl.ChicagoClam;
import abstractfactory.ingredient.impl.ChicagoDough;
import abstractfactory.ingredient.impl.ChicagoPepperoni;
import abstractfactory.ingredient.impl.ChicagoSauce;
import abstractfactory.ingredient.impl.VeggieGarlic;
import abstractfactory.ingredient.impl.VeggieOnion;/*** 芝加哥原料工厂 **/
public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory{@Overridepublic Dough createDough() {return new ChicagoDough();}@Overridepublic Sauce createSauce() {return new ChicagoSauce();}@Overridepublic Cheese createCheese() {return new ChicagoCheese();}@Overridepublic Veggies[] createVeggies() {Veggies[] veggies = {new VeggieGarlic(), new VeggieOnion()};return veggies;}@Overridepublic Pepperoni createPepperoni() {return new ChicagoPepperoni();}@Overridepublic Clam createClam() {return new ChicagoClam();}}
 
Pizza类
package abstractfactory.pizza;import java.util.ArrayList;import abstractfactory.ingredient.Cheese;
import abstractfactory.ingredient.Clam;
import abstractfactory.ingredient.Dough;
import abstractfactory.ingredient.Pepperoni;
import abstractfactory.ingredient.Sauce;
import abstractfactory.ingredient.Veggies;public abstract class Pizza {String name;//名称/*** Pizza制作中需要用到的各种原料*/Dough dough;//面团Sauce sauce;//果酱Veggies veggies;//蔬菜Cheese cheese;//奶酪Pepperoni pepperoni;//香肠切片Clam clam;//蚌ArrayList<String> toppings = new ArrayList<String>();//若干佐料/*** 需要被子类实现的接口(设计模式中,接口的意思:一个抽象方法,一个interface,或一个抽象类)* 子类在实现时,将利用自己的工厂来创建自己的产品(Dough,Sauce,Veggies,Cheese等的具体类)*/public abstract void prepare();public void bake() {System.out.println("Bake for 25 minutes");}public void cut() {System.out.println("Cutting the pizza into diagonal slices");}public void box() {System.out.println("Place pizza in official PizzaStore box");}public void setName(String name) {this.name = name;}public String getName() {return name;}
}
 
具体的Pizza---NYStyleCheesePizza
package abstractfactory.pizza;import abstractfactory.PizzaIngredientFactory;/*** 通过抽象工厂完成对一组原料的实例化**/
public class NYStyleCheesePizza extends Pizza {//与原料工厂进行组合PizzaIngredientFactory ingredientFactory;//---抽象工厂模式public NYStyleCheesePizza(PizzaIngredientFactory ingredientFactory) {this.ingredientFactory = ingredientFactory;}/*** 运行时将由传入的具体原料工厂完成对应原料的创建*/@Overridepublic void prepare() {System.out.println("Preparing "+name);//通过原料工厂,对从父类继承下来的那些属性进行初始化dough = ingredientFactory.createDough();sauce = ingredientFactory.createSauce();cheese = ingredientFactory.createCheese();}}
 
具体的Pizza---ChicagoStyleCheesePizza
package abstractfactory.pizza;import abstractfactory.PizzaIngredientFactory;/*** 通过抽象工厂完成对一组原料的实例化**/
public class ChicagoStyleCheesePizza extends Pizza {//与原料工厂进行组合PizzaIngredientFactory ingredientFactory;//---抽象工厂模式public ChicagoStyleCheesePizza(PizzaIngredientFactory ingredientFactory) {this.ingredientFactory = ingredientFactory;}/*** 覆盖父类的方法*/@Overridepublic void cut() {System.out.println("Cutting the pizza into square slices");}/*** 运行时将由传入的具体原料工厂完成对应原料的创建*/@Overridepublic void prepare() {System.out.println("Preparing "+name);//通过原料工厂,对从父类继承下来的那些属性进行初始化dough = ingredientFactory.createDough();sauce = ingredientFactory.createSauce();cheese = ingredientFactory.createCheese();clam = ingredientFactory.createClam();}}
 
PizzaStore
package abstractfactory.store;import abstractfactory.pizza.Pizza;public abstract class PizzaStore {/*** 订购Pizza的流程是久经考验的,用final修饰,不允许子类进行改变!* * 提供了一般的框架(定义好流程),以便创建Pizza* 依赖抽象工厂方法创建具体的子类,并创建出实际的Pizza*/final public Pizza orderPizza(String type) {//依赖与抽象Pizza pizza;//超类型/父类/接口//调用抽象工厂方法,在运行时由具体的子类来返回实例对象pizza = createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}/*** 工厂移到这里了,不再单独定义,而是用一个方法(抽象工厂方法)完成对象的创建* 具体对象由子类根据各自的需求进行返回---解耦* * 参数化工厂方法,参数错误将发生运行时异常* 解决办法:使用枚举类型作为参数,在编译期对参数进行检查* @return 具体的子类对象*/abstract Pizza createPizza(String type);//---工厂方法模式
}
 
具体的PizzaStore----NYPizzaStore
package abstractfactory.store;import abstractfactory.NYPizzaIngredientFactory;
import abstractfactory.PizzaIngredientFactory;
import abstractfactory.pizza.NYStyleCheesePizza;
import abstractfactory.pizza.Pizza;public class NYPizzaStore extends PizzaStore {/*** 子类对抽象方法进行实现---工厂方法模式* 返回自己需要的对象*/@OverridePizza createPizza(String type) {Pizza pizza = null;//引入New York的原料工厂//工厂在方法中被指定,外部并不需要知道PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();if(type.equals("cheese")) {pizza = new NYStyleCheesePizza(ingredientFactory);pizza.setName("New York Style Cheese Pizza from abstract factory!");return pizza;}return null;}}
 
具体的PizzaStore----ChicagoPizzaStore
package abstractfactory.store;import abstractfactory.ChicagoPizzaIngredientFactory;
import abstractfactory.PizzaIngredientFactory;
import abstractfactory.pizza.ChicagoStyleCheesePizza;
import abstractfactory.pizza.Pizza;public class ChicagoPizzaStore extends PizzaStore {/*** 子类对抽象方法进行实现---工厂方法模式* 返回自己需要的对象*/@OverridePizza createPizza(String type) {Pizza pizza = null;//引入Chicago的原料工厂//工厂在方法中被指定,外部并不需要知道PizzaIngredientFactory ingredientFactory = new ChicagoPizzaIngredientFactory();if(type.equals("cheese")) {pizza = new ChicagoStyleCheesePizza(ingredientFactory);pizza.setName("Chicago Style Cheese Pizza from abstract factory!");return pizza;}return null;}}
 
测试
package test;import abstractfactory.store.ChicagoPizzaStore;
import abstractfactory.store.NYPizzaStore;
import abstractfactory.store.PizzaStore;public class PizzaTest {public static void main(String[] args) {orderNYStylePizza();System.out.println("==========================");orderChicagoStylePizza();}private static void orderChicagoStylePizza() {PizzaStore store = new ChicagoPizzaStore();store.orderPizza("cheese");}private static void orderNYStylePizza() {PizzaStore store = new NYPizzaStore();store.orderPizza("cheese");}}
 

 

 

 

  相关解决方案