当有一堆对象等着被实例化,究竟实现哪个类,需要在运行时由一些条件来决定!
如果代码是针对接口编写的,那么通过多态的特性,它就能与任何新的实现类进行绑定,从而实现扩展!
找出会变化的地方,把它们从不变的部分分离出来,单独进行设计!
工厂方法研究:
如何将实例化具体类的代码从应用中抽离,或者封装起来,使它们不会干扰其它部分。
每当需求发生变化或者有新的需求时,你必须对原来的代码进行修改才能完成对需求的实现,如果是这样的话,你应该意识到:你的系统在设计上存在严重问题!!!
对修改没关闭,对扩展没开放,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 { @Override void prepare() { System.out.println("prepare CheesePizza"); } @Override void bake() { System.out.println("bake CheesePizza"); } @Override void cut() { System.out.println("cut CheesePizza"); } @Override void box() { System.out.println("box CheesePizza"); } }
package staticfactory; public class ClamPizza extends Pizza { @Override void prepare() { System.out.println("prepare ClamPizza"); } @Override void bake() { System.out.println("bake ClamPizza"); } @Override void cut() { System.out.println("cut ClamPizza"); } @Override void box() { System.out.println("box ClamPizza"); } }
package staticfactory; public class VeggiePizza extends Pizza { @Override void prepare() { System.out.println("prepare VeggiePizza"); } @Override void bake() { System.out.println("bake VeggiePizza"); } @Override void cut() { System.out.println("cut VeggiePizza"); } @Override void 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);//委托工厂创建Pizza pizza.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"); } /** * 覆盖父类的方法 */ @Override public 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 { /** * 子类对抽象方法进行实现 * 返回自己需要的对象 */ @Override Pizza 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 { /** * 子类对抽象方法进行实现 * 返回自己需要的对象 */ @Override Pizza 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{ @Override public Dough createDough() { return new NYDough(); } @Override public Sauce createSauce() { return new NYSauce(); } @Override public Cheese createCheese() { return new NYCheese(); } @Override public Veggies[] createVeggies() { Veggies[] veggies = {new VeggieGarlic(), new VeggieOnion()}; return veggies; } @Override public Pepperoni createPepperoni() { return new NYPepperoni(); } @Override public 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{ @Override public Dough createDough() { return new ChicagoDough(); } @Override public Sauce createSauce() { return new ChicagoSauce(); } @Override public Cheese createCheese() { return new ChicagoCheese(); } @Override public Veggies[] createVeggies() { Veggies[] veggies = {new VeggieGarlic(), new VeggieOnion()}; return veggies; } @Override public Pepperoni createPepperoni() { return new ChicagoPepperoni(); } @Override public 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; } /** * 运行时将由传入的具体原料工厂完成对应原料的创建 */ @Override public 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; } /** * 覆盖父类的方法 */ @Override public void cut() { System.out.println("Cutting the pizza into square slices"); } /** * 运行时将由传入的具体原料工厂完成对应原料的创建 */ @Override public 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 { /** * 子类对抽象方法进行实现---工厂方法模式 * 返回自己需要的对象 */ @Override Pizza 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 { /** * 子类对抽象方法进行实现---工厂方法模式 * 返回自己需要的对象 */ @Override Pizza 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"); } }