用抽象工厂模式开奶茶店
相关概念
- 产品等级结构 :产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
- 产品族 :在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
参考:https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/abstract_factory.html
定义
抽象工厂模式提供一个接口,用于创建相关或依赖对象的产品族,而不需要明确指定具体类。
这个定义可能一下看不太懂,结合后面例子就容易理解很多。
应用场景
当工厂需要生产出产品族时,使用抽象工厂模式。当工厂不生产产品族而只负责生产一类产品时抽象工厂模式退化为工厂方法模式。
比如页面的风格变换,往往需要多个组件的同时修改,此时用抽象工厂模式,则每一个具体工厂负责一种风格,替换风格只需替换具体工厂即可。
例子
我们用奶茶做例子。
一个奶茶制造工厂,它可以同时提供牛奶和茶,但不同地方的奶茶工厂选用的牛奶和茶的品种都不一样,因为不是所有的牛奶都叫特仑苏。一点点和喜茶从不同额奶茶工厂中拿到奶茶原料,我们用程序模拟这个情况,下面是uml类图。
Milk接口定义了牛奶产品等级结构的方法,Tea解耦定义了茶产品等级结构的方法。MilkTeaFactory接口定义了奶茶工厂的方法,方法返回的值类型是抽象接口,所以调用的客户在编译期并不知道返回的茶和奶的具体类型是什么,只有在运行时运用多态的技术才能知道具体是哪种奶和茶。这就实现了针对接口编程而不是针对具体编程。
下面是代码
Tea.java
package priv.mxz.design_pattern.abstract_factory_pattern;
interface Tea {
String getType();
}
class GreenTea implements Tea{
@Override
public String getType() {
return "绿茶";
}
}
class BlackTea implements Tea{
@Override
public String getType() {
return "红茶";
}
}
Milk.java
package priv.mxz.design_pattern.abstract_factory_pattern;
interface Milk {
String getCompany();
}
class MengniuMilk implements Milk{
@Override
public String getCompany() {
return "蒙牛公司";
}
}
class YiliMilk implements Milk{
@Override
public String getCompany() {
return "伊利公司";
}
}
MilkTeaFactory.java
package priv.mxz.design_pattern.abstract_factory_pattern;
interface MilkTeaFactory {
Tea getTea();
Milk getMilk();
}
class MilkTeaFactoryA implements MilkTeaFactory{
@Override
public Tea getTea() {
return new GreenTea();
}
@Override
public Milk getMilk() {
return new MengniuMilk();
}
}
class MilkTeaFactoryB implements MilkTeaFactory{
@Override
public Tea getTea() {
return new BlackTea();
}
@Override
public Milk getMilk() {
return new YiliMilk();
}
}
MilkTeaShop.java
package priv.mxz.design_pattern.abstract_factory_pattern;
class MilkTeaShop{
private MilkTeaFactory milk_tea_factory;
private String shop_name;
public MilkTeaShop(MilkTeaFactory mtf,String shop_name){
milk_tea_factory=mtf;
this.shop_name=shop_name;
}
public void makeMilkTea(){
System.out.println("MilkTeaShop "+ shop_name+ " make a milk tea with ");
System.out.println(milk_tea_factory.getMilk().getCompany());
System.out.println(milk_tea_factory.getTea().getType());
}
}
AbstractFactoryPattern.java
package priv.mxz.design_pattern.abstract_factory_pattern;
public class AbstractFactoryPattern {
public static void main(String[] args) {
MilkTeaShop yidiandian=new MilkTeaShop(new MilkTeaFactoryA(), "一点点");
MilkTeaShop xicha=new MilkTeaShop(new MilkTeaFactoryB(),"喜茶");
yidiandian.makeMilkTea();
xicha.makeMilkTea();
}
}
结果
MilkTeaShop 一点点 make a milk tea with
蒙牛公司
绿茶
MilkTeaShop 喜茶 make a milk tea with
伊利公司
红茶
AbstractFactoryPattern.java中有函数入口,可以看到,不同的奶茶店通过绑定不同的奶茶工厂就得到了不同的牛奶和茶。
优缺点
优点:
抽象工厂模式很好地解释了什么是面向接口编程,工厂处理的是产品的抽象类或接口,客户也是针对抽象工厂来编程。
添加新的工厂与产品非常方便,不需要修改已有的工厂类和产品类,符合开闭原则
缺点:
工厂生产出来的产品族种类难改变,如果想要新生产另一类产品,则需要修改抽象工厂接口,同时修改所有具体工厂的实现
总结
抽象工厂模式是工厂模式系列的最终版,工厂可以生产出一个产品族,当只生产一种产品时,抽象工厂模式退化为工厂方法模式。抽象工厂模式的抽象在于无论是工厂还是客户都是面向接口编程,不涉及具体的类。抽象工厂模式添加新的工厂生产相同品种的产品很容易,但要工厂生产新类型的产品则很困难。