定义
定义一个用于创建对象的接口,让子类决定实例化哪个类。
使用场景
在任何需要生成复杂对象的地方,都可以使用工厂方法模式。
UML类图
一个非常贴近生活的例子来告诉你什么是工厂模式
看到上面的定义,我相信有很多人都不明白工厂模式存在的意义到底是什么?工厂模式的存在确实是为了创建实例,但是为什么要通过工厂来创建呢,为什么不直接new一个对象呢?看起来似乎多此一举,可这真的是多此一举吗?下面我们来看两个具体的例子,通过这两个例子慢慢分析并解答我们上面所提的这些问题?
创建一个抽象动物类:Animal
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package com.akathink.designpattern.entity; * 动物类 * @author LiuQingJie * */ public abstract class Animal { private String name; public Animal() { super(); } public Animal(String name) { super(); this.name = name; } public abstract void eat(); public String getName() { return name; } public void setName(String name) { this.name = name; } }
|
创建一个具体的动物类:Cat
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.akathink.designpattern.entity; * 猫类 * @author LiuQingJie * */ public class Cat extends Animal { public Cat() { super(); } public Cat(String name){ super(name); } @Override public void eat() { System.out.println("我的名字是:" + getName() + ",喵!!"+ "I like to eat fish!"); } }
|
创建一个具体的动物类:Dog
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.akathink.designpattern.entity; * 狗类 * @author LiuQingJie * */ public class Dog extends Animal { public Dog() { super(); } public Dog(String name){ super(name); } @Override public void eat() { System.out.println("我的名字是:" + getName() + ",汪汪!!"+ "I like to eat bone!"); } }
|
创建一个抽象动物工厂类:AbstractAnimalFactory
1 2 3 4 5 6 7 8 9 10 11
| package com.akathink.designpattern; import com.akathink.designpattern.entity.Animal; * 抽象动物工厂:用来生产小动物 * @author LiuQingJie * */ public abstract class AbstractAnimalFactory { public abstract <T extends Animal> T createAnimal(Class<T> c); }
|
创建一个具体动物工厂类:AnimalFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.akathink.designpattern; import com.akathink.designpattern.entity.Animal; /** * 动物工厂:用来生产小动物 * @author LiuQingJie * */ public class AnimalFactory extends AbstractAnimalFactory { @SuppressWarnings("unchecked") @Override public <T extends Animal> T createAnimal(Class<T> c) { Animal animal = null; try { animal = (T)Class.forName(c.getName()).newInstance(); } catch (Exception e) { e.printStackTrace(); } return (T) animal; } }
|
创建一个工厂模式场景类:FactoryPattern
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package com.akathink.designpattern; import com.akathink.designpattern.entity.Animal; import com.akathink.designpattern.entity.Cat; import com.akathink.designpattern.entity.Dog; * 工厂模式场景类 * @author LiuQingJie * */ public class FactoryPattern { public static void main(String[] args) { AbstractAnimalFactory animalFactory = new AnimalFactory(); Animal cat = animalFactory.createAnimal(Cat.class); cat.setName("Tom"); cat.eat(); Animal dog = animalFactory.createAnimal(Dog.class); dog.setName("哮天犬"); dog.eat(); } }
|
运行结果:
1 2
| 我的名字是:Tom,喵!!I like to eat fish! 我的名字是:哮天犬,汪汪!!I like to eat bone!
|
上面这个例子确实是采用工厂模式来实现的,但是我们依然看不出来,为什么要采用工厂模式来实现,这样实现的好处有哪些?网上各大博客关于工厂模式的例子很多都和此类似,并没能具体说明,更甚者没能说明白工厂模式到底使用在什么地方。其实工厂模式在我们现实生活中非常常见,下面举的这个例子将会告诉大家工厂模式到底用在哪里?
相信大家都去过麦当劳吧,我们去点餐的时候,可以点一份香草奶昔、一份麦辣鸡翅,再加一杯咖啡,也可以点一个吉士汉堡包和一杯可口可乐。具体要点哪些,我们可以随意挑、随意点,挑完之后直接告诉点餐员,然后付款就OK了。这时候我们可能发现这不是传说中的建造者模式吗?与工厂模式有什么关系呢?建造者模式与工厂模式确实没啥太大关系,但是通过这个例子却同时可以引出我们的工厂模式。好了,工厂模式隆重现身。
有的时候我们上班都很累,上完一天的班了就是一阵猛饿,到了麦当劳之后,发现自己并不知到吃啥(不会饿昏了头吧),怎么办呢,没办法,就叫一份今日推荐的麦辣鸡腿汉堡超值套餐吧。这个时候我们并不需要把套餐里面的每类食物都再说一遍,只需要点这一份套餐就可以了。
假设我们现在只提供三种类型点食物:汉堡、饮料、小吃
汉堡(巨无霸、吉士汉堡、双层吉士汉堡)
1 2 3 4 5 6 7
| package com.akathink.designpattern.entity; * 汉堡 */ public interface IBurgers { String makeBurger(); }
|
1 2 3 4 5 6 7 8 9 10
| package com.akathink.designpattern.entity; public class BigMac implements IBurgers { @Override public String makeBurger() { return "巨无霸"; } }
|
1 2 3 4 5 6 7 8 9 10
| package com.akathink.designpattern.entity; public class CheeseBurger implements IBurgers { @Override public String makeBurger() { return "吉士汉堡包"; } }
|
1 2 3 4 5 6 7 8 9 10
| package com.akathink.designpattern.entity; public class DoubleCheeseBurger implements IBurgers { @Override public String makeBurger() { return "双层吉士汉堡"; } }
|
饮料(可乐、牛奶、橙汁)
1 2 3 4 5 6 7
| package com.akathink.designpattern.entity; * 饮料 */ public interface IBeverages { String makeDrinking(); }
|
1 2 3 4 5 6 7 8 9 10
| package com.akathink.designpattern.entity; public class Coke implements IBeverages { @Override public String makeDrinking() { return "可乐"; } }
|
1 2 3 4 5 6 7 8 9 10
| package com.akathink.designpattern.entity; public class Milk implements IBeverages { @Override public String makeDrinking() { return "牛奶"; } }
|
1 2 3 4 5 6 7 8 9 10
| package com.akathink.designpattern.entity; public class OrangeJuice implements IBeverages { @Override public String makeDrinking() { return "橙汁"; } }
|
小吃(奶昔、巧克力奶昔、苹果派)
1 2 3 4 5 6 7 8
| package com.akathink.designpattern.entity; * 小吃 */ public interface ISnacks { String makeSnack(); }
|
1 2 3 4 5 6 7 8 9 10
| package com.akathink.designpattern.entity; public class MilkSnack implements ISnacks { @Override public String makeSnack() { return "奶昔"; } }
|
1 2 3 4 5 6 7 8 9 10
| package com.akathink.designpattern.entity; public class ChocolateSnack implements ISnacks { @Override public String makeSnack() { return "巧克力奶昔" ; } }
|
1 2 3 4 5 6 7 8 9 10
| package com.akathink.designpattern.entity; public class ApplePie implements ISnacks { @Override public String makeSnack() { return "苹果派"; } }
|
食物准备好了,还需要一个订单类,因为这些食物都是客户自选组合点,所以我们点订单类可以使用建造者模式,更多关于建造者模式,请关注下一篇设计模式文章。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| package com.akathink.designpattern; import com.akathink.designpattern.entity.IBeverages; import com.akathink.designpattern.entity.IBurgers; import com.akathink.designpattern.entity.ISnacks; public class Order { private IBurgers mBurger; private IBeverages mBeverages; private ISnacks mSnack; private Order(OrderBuilder builder) { mBurger = builder.mBurger; mBeverages = builder.mBeverages; mSnack = builder.mSnack; } public String makeOrder() { StringBuilder sb = new StringBuilder(); if (mBurger != null) { sb.append(mBurger.makeBurger()).append(" "); } if (mBeverages != null) { sb.append(mBeverages.makeDrinking()).append(" "); } if (mSnack != null) { sb.append(mSnack.makeSnack()); } return sb.toString(); } public static class OrderBuilder { private IBurgers mBurger; private IBeverages mBeverages; private ISnacks mSnack; public OrderBuilder() { } public OrderBuilder addBurger(IBurgers burgers) { this.mBurger = burgers; return this; } public OrderBuilder addBeverage(IBeverages beverages) { this.mBeverages = beverages; return this; } public OrderBuilder addSnack(ISnacks snacks) { this.mSnack = snacks; return this; } public Order build() { return new Order(this); } } }
|
订单工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.akathink.designpattern; import com.akathink.designpattern.entity.ApplePie; import com.akathink.designpattern.entity.BigMac; import com.akathink.designpattern.entity.CheeseBurger; import com.akathink.designpattern.entity.ChocolateSnack; import com.akathink.designpattern.entity.Coke; import com.akathink.designpattern.entity.DoubleCheeseBurger; import com.akathink.designpattern.entity.Milk; import com.akathink.designpattern.entity.MilkSnack; import com.akathink.designpattern.entity.OrangeJuice; public class OrderFactory { public static Order createBigMacCombo() { return new Order.OrderBuilder().addBurger(new BigMac()).addBeverage(new Coke()).addSnack(new ApplePie()) .build(); } public static Order createCheeseBurgerCombo() { return new Order.OrderBuilder().addBurger(new CheeseBurger()).addBeverage(new Milk()).addSnack(new MilkSnack()) .build(); } public static Order createDoubleBurgerCombo() { return new Order.OrderBuilder().addBurger(new DoubleCheeseBurger()).addBeverage(new OrangeJuice()) .addSnack(new ChocolateSnack()).build(); } }
|
场景类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.akathink.designpattern; public class FactoryClient { public static void main(String[] args) { Order bigMacComboOrder = OrderFactory.createBigMacCombo(); System.out.println(bigMacComboOrder.makeOrder()); Order cheeseBurgerComboOrder = OrderFactory.createCheeseBurgerCombo(); System.out.println(cheeseBurgerComboOrder.makeOrder()); Order DoubleBurgerComboOrder = OrderFactory.createDoubleBurgerCombo(); System.out.println(DoubleBurgerComboOrder.makeOrder()); } }
|
运行结果:
1 2 3
| 巨无霸 可乐 苹果派 吉士汉堡包 牛奶 奶昔 双层吉士汉堡 橙汁 巧克力奶昔
|
至此,我们可以发现,如果我们点一份套餐,可以很容易创建一个实例对象,而不用去关心创建这个对象时需要配置哪些东西,或者内部是如何创建的。这样就把一个复杂的对象交给工厂类来负责了,同时通过工厂类,我们也能快速了解我们的工厂能够创建哪些对象,换句话也就是能够提供哪些服务。假如以后我们工厂里面的某个服务更改了,只需要更改工厂模式一处位置就可以了,也就实现了可维护性。
所以,回归到工厂模式的应用场景:在任何需要生成复杂对象的地方,都可以使用工厂方法模式。
工厂模式的优点
优点
- 良好的封装性,代码结构清晰。创建一个对象是有条件约束的,假如我们需要创建一个具体的对象,只要知道这个产品的类名就可以了,不用知道创建对象的艰辛过程,降低模块间的耦合。
- 扩展性强。假如我们想要增加一个产品类,只要适当的修改具体的工厂类,或者扩展一个工厂类,就可以完成“拥抱变化”。
- 屏蔽产品类。产品类的实现如何变化,调用者不需要关心,只需要关心产品的接口就行了。
- 工厂方法模式是典型的解耦框架。高层模块需要知道产品的抽象类,其他的实现类都不需要关心,符合迪米特原则;也符合依赖倒置原则,只依赖产品的抽象;当然也符合里氏替换原则,使用产品子类替换产品父类是没有任何问题的。
参考资料
《设计模式之禅》
《大话设计模式》
《Android源码设计模式》
http://blog.csdn.net/renhui999/article/details/8482977
http://blog.csdn.net/nugongahou110/article/details/50425823
http://blog.csdn.net/lovelion/article/details/9300731