本文示例代码材料源自Head First设计模式
以前整理自己整理的链接:
工厂模式
/u011109881/article/details/56541580
抽象工厂
/u011109881/article/details/56730497
实例
假设现在要生产各种各样的Pizza,Pizza有不同的原料,就可以做出不同的Pizza,Pizza需要经过材料准备 烘焙 切片 打包等诸多过程。
没有学习设计模式之前,我们的代码可能是这样的:
public class PizzaStore {Pizza orderPizza(String type) {Pizza pizza;switch (type) {case "cheese":pizza = new CheesePizza();break;case "greek":pizza = new GreekPizza();break;default:pizza = new CheesePizza();break;}pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}}
public class Pizza {public void prepare(){System.out.println("prepare");};public void bake(){System.out.println("bake");};public void cut(){System.out.println("cut");};public void box(){System.out.println("box");};}
但是请思考一下,这样的代码易于扩展么?
比如我们要新加几种Pizza,原先的Pizza由于销量不好全部下架。那么我们只好进入orderPizza内部,对其进行一次“大手术”,而这违反了设计原则的对修改关闭对扩展开放的原则。
使用简单工厂(不算设计模式 只能算技巧)
我们再分析一下orderPizza的代码,可以发现生产Pizza的部分可能会经常变动,而包装过程不怎么变动。那么我们可不可以将变化的部分抽出来呢?
简单工厂类图
把变化的部分抽离出来,就是利用了简单工厂的思想。它的结构如下:
public class SimplePizzaFactory {public Pizza createPizza(String type){Pizza pizza;switch (type) {case "cheese":pizza = new CheesePizza();break;case "greek":pizza = new GreekPizza();break;default:pizza = new CheesePizza();break;}return pizza;}}
public class PizzaStore {SimplePizzaFactory factory;public PizzaStore(SimplePizzaFactory factory) {this.factory = factory;}Pizza orderPizza(String type) {Pizza pizza;pizza = factory.createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}}
聪明的读者也许一下子就会发现问题:这丫的不是自欺欺人掩耳盗铃么。没错,你是把变化的部分抽离了,放到了SimplePizzaFactory里面,但是这不过是把问题从一个地方转移到另一个地方么?问题仍然存在啊?
其实这样做有利于复用SimplePizzaFactory的代码,比如其他使用者需要对Pizza进行不同的加工。比如在门店购买的Pizza和饿了么送货的Pizza的处理应该不会相同。这样既分离了变化和不变的部分,又达成代码复用的目的。
在上面这个例子中PizzaStore中组合了SimplePizzaFactory对象,SimplePizzaFactory对象则组合了Pizza对象,Pizza对象又是各类Pizza的基类。简单工厂就是利用组合方式来分离变化与不变的部分的。
引入地域风情
现在,Pizza连锁店生意兴隆,风靡全国各地。比如上海苏州的Pizza会偏甜,湖南重庆的Pizza可能会放辣椒。
对于这种新加的元素,可以使用工厂模式。
使用工厂模式
类图:
(由于ProcessOn不能实现单个方法斜体,因此将抽象方法前面加上< A >表示抽象方法)
工厂模式代码实例
创建者类(creator)
public abstract class PizzaStore {Pizza pizza;public PizzaStore() {}public Pizza orderPizza(String type) {pizza = createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}public abstract Pizza createPizza(String type);}
public class CQPizzaStore extends PizzaStore{public CQPizzaStore() {}@Overridepublic Pizza createPizza(String type) {switch (type) {case "cheese":pizza = new CQCheesePizza();break;case "greek":pizza = new CQGreekPizza();break;default:pizza = new CQCheesePizza();break;}return pizza;}}
public class SHPizzaStore extends PizzaStore{public SHPizzaStore() {}@Overridepublic Pizza createPizza(String type) {switch (type) {case "cheese":pizza = new SHCheesePizza();break;case "greek":pizza = new SHGreekPizza();break;default:pizza = new SHCheesePizza();break;}return pizza;}}
产品类
public abstract class Pizza {String name;String dough;String sauce;ArrayList<String> toppings = new ArrayList<String>();public void prepare(){System.out.println("prepare "+ name);System.out.println("prepare Tossing "+dough);System.out.println("prepare Adding"+ sauce);System.out.println("prepare Adding toppings:");for(int i=0;i<toppings.size();i++){System.out.println(" "+toppings.get(i));}};public void bake(){System.out.println("bake");};public void cut(){System.out.println("cut");};public void box(){System.out.println("box");};public String getName(){return name;}}
public class CQCheesePizza extends Pizza{public CQCheesePizza(){name = "CQ Style Sauce and Cheese Pizza";dough = "Extar Thick Crust Dugh";sauce ="Plum Tomato Sauce";toppings.add("老干妈");}}
public class CQGreekPizza extends Pizza{public CQGreekPizza(){name = "CQ Style Sauce and Greek Pizza";dough = "Extar Thick Crust Dugh";sauce ="Plum Tomato Sauce";toppings.add("老干妈");}}
public class SHCheesePizza extends Pizza{public SHCheesePizza(){name = "SH Style Sauce and CHeese Pizza";dough = "Thin Crust Dugh";sauce ="Marinar Sauce";toppings.add("甜酱");}}
public class SHGreekPizza extends Pizza{public SHGreekPizza(){name = "SH Style Sauce and Greek Pizza";dough = "Thin Crust Dugh";sauce ="Marinar Sauce";toppings.add("甜酱");}}
测试类
public class Test {public static void main(String[] args) {PizzaStore store = new CQPizzaStore();CQCheesePizza cqCheese = (CQCheesePizza) store.orderPizza("cheese");System.out.println();CQGreekPizza cqGreek = (CQGreekPizza) store.orderPizza("greek");System.out.println();store = new SHPizzaStore();SHCheesePizza shCheese = (SHCheesePizza) store.orderPizza("cheese");System.out.println();SHGreekPizza shGreek = (SHGreekPizza) store.orderPizza("greek");System.out.println();}}
测试结果:
prepare CQ Style Sauce and Cheese Pizzaprepare Tossing Extar Thick Crust Dughprepare AddingPlum Tomato Sauceprepare Adding toppings:老干妈bakecutboxprepare CQ Style Sauce and Greek Pizzaprepare Tossing Extar Thick Crust Dughprepare AddingPlum Tomato Sauceprepare Adding toppings:老干妈bakecutboxprepare SH Style Sauce and CHeese Pizzaprepare Tossing Thin Crust Dughprepare AddingMarinar Sauceprepare Adding toppings:甜酱bakecutboxprepare SH Style Sauce and Greek Pizzaprepare Tossing Thin Crust Dughprepare AddingMarinar Sauceprepare Adding toppings:甜酱bakecutbox
使用抽象工厂模式
抽象工厂模式类图
代码示例
原料基类
public class Cheese {}
public class Clams {}
public class Dough {}
public class Pepperoni {}
public class Sauce {}
public class Veggies {}
原料实体类(部分略)
public class PepperyCheese extends Cheese {}
public class PepperyClam extends Clams{}
public class PepperyDough extends Dough {}
public class PepperyPepperoni extends Pepperoni {}
public class PepperySauce extends Sauce {}
public class RedPepper extends Veggies {}
原料工厂类
public interface PizzaIngedientFactory {public Dough createDough();public Clams createClams();public Cheese createCheese();public Pepperoni createPepperoni();public Sauce createSauce();public Veggies[] createVeggies();}
public class NYPizzaIngedientFactory implements PizzaIngedientFactory {@Overridepublic Dough createDough() {System.out.println("createDough");return new ThinCrustDough();}@Overridepublic Clams createClams() {System.out.println("createClams");return new FreshClam();}@Overridepublic Cheese createCheese() {System.out.println("createCheese");return new ReggianoCheese();}@Overridepublic Pepperoni createPepperoni() {System.out.println("createPepperoni");return new SlicedPepperoni();}@Overridepublic Sauce createSauce() {System.out.println("createSauce");return new MarinaraSauce();}@Overridepublic Veggies [] createVeggies() {System.out.println("createVeggies");Veggies veggies [] = {new Garlic() , new Onion(),new Mushroom(),new RedPepper()};return veggies;}}
public class CQPizzaIngedientFactory implements PizzaIngedientFactory {@Overridepublic Dough createDough() {System.out.println("createDough PepperyDough");return new PepperyDough();}@Overridepublic Clams createClams() {System.out.println("createClams PepperyClam");return new PepperyClam();}@Overridepublic Cheese createCheese() {System.out.println("createCheese PepperyCheese");return new PepperyCheese();}@Overridepublic Pepperoni createPepperoni() {System.out.println("createPepperoni PepperyPepperoni");return new PepperyPepperoni();}@Overridepublic Sauce createSauce() {System.out.println("createSauce PepperySauce");return new PepperySauce();}@Overridepublic Veggies [] createVeggies() {System.out.println("createVeggies");Veggies veggies [] = {new Garlic() , new Onion(),new Mushroom(),new RedPepper()};return veggies;}}
Pizza类
public abstract class Pizza {String name;Dough dough;Sauce sauce;Cheese cheese;Clams clam;ArrayList<Veggies> veggies = new ArrayList<Veggies>();PizzaIngedientFactory ingedientFactory;public abstract void prepare();public void bake(){System.out.println("bake");};public void cut(){System.out.println("cut");};public void box(){System.out.println("box");};public void setName(String name){this.name = name;}public String getName(){return name;}@Overridepublic String toString() {return name;}}
public class CheesePizza extends Pizza {public CheesePizza(PizzaIngedientFactory ingedientFactory){this.ingedientFactory = ingedientFactory;}@Overridepublic void prepare() {System.out.println("Preparing "+name);dough = ingedientFactory.createDough();sauce = ingedientFactory.createSauce();cheese = ingedientFactory.createCheese();}}
public class ClamPizza extends Pizza {public ClamPizza(PizzaIngedientFactory ingedientFactory){this.ingedientFactory = ingedientFactory;}@Overridepublic void prepare() {System.out.println("Preparing "+name);dough = ingedientFactory.createDough();sauce = ingedientFactory.createSauce();cheese = ingedientFactory.createCheese();clam = ingedientFactory.createClams();}}
店铺类
public abstract class PizzaStore {Pizza pizza;public PizzaStore() {}public Pizza orderPizza(String type) {pizza = createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}public abstract Pizza createPizza(String type);}
public class CQPizzaStore extends PizzaStore{@Overridepublic Pizza createPizza(String type) {PizzaIngedientFactory cqPizzaIngedientFactory = new CQPizzaIngedientFactory();switch (type) {case "cheese":pizza = new CheesePizza(cqPizzaIngedientFactory);pizza.setName("CQ cheese Pizza");break;case "clam":pizza = new ClamPizza(cqPizzaIngedientFactory);pizza.setName("CQ clam Pizza");break;}return pizza;}}
public class NYPizzaStore extends PizzaStore{@Overridepublic Pizza createPizza(String type) {PizzaIngedientFactory nyPizzaIngedientFactory = new NYPizzaIngedientFactory();switch (type) {case "cheese":pizza = new CheesePizza(nyPizzaIngedientFactory);pizza.setName("NY cheese Pizza");break;case "clam":pizza = new ClamPizza(nyPizzaIngedientFactory);pizza.setName("NY clam Pizza");break;}return pizza;}}
测试类
public class Test {public static void main(String[] args) {PizzaStore store = new NYPizzaStore();CheesePizza nyCheesePizza = (CheesePizza) store.orderPizza("cheese");System.out.println();ClamPizza nyClamPizza = (ClamPizza) store.orderPizza("clam");System.out.println();PizzaStore store2 = new CQPizzaStore();CheesePizza cqCheesePizza = (CheesePizza) store2.orderPizza("cheese");System.out.println();ClamPizza cqClamPizza = (ClamPizza) store2.orderPizza("clam");System.out.println();}}
关于工厂模式和抽象工厂模式的区别和联系
从上述工厂模式和抽象工厂模式的UML类图来看,其实工厂模式是存在于抽象工厂模式里面的。注意看如下共通部分:
工厂模式截图
抽象工厂模式部分截图
两种模式都是通过PizzaStore来生产产品。只不过,抽象工厂模式更为复杂一些。因为,它包含了一系列的产品原料,它更适合于生产零件很多,不同搭配可以生产不同产品的情况。
另外,这两种模式都包含生产对象的方法(本例中是createPizza方法),子类只要继承并实现该方法,就可以生产对象了,因此他们都是用于生产对象的模式,只不过抽象工厂模式中间加入了一个工厂来生成对象,他们将需要产品的客户端(本例中为测试类)与实际产品(本例中是Pizza)解耦。
所以工厂模式和抽象工厂模式还是很像的,区别相对较小。