运行结果同上,这就是 简单工厂
模式,由 抽象产品
、具体产品
、工厂
三个要素组成,工厂内有具体的逻辑去判断生成怎么样的产品。
另外,如果奶茶实例可以服用的话,为了节省内存和对象创建时间,可以将其事先创建好缓存起来,调用createTea()时,从缓存中直接取出parse对象直接使用。
public class NewTeaStore { private static final Map<Integer, Tea> cachedTeas = new HashMap<>(); static { cachedTeas.put(0, new TapiocaMilkTea()); cachedTeas.put(1, new HKStyleHotTea()); cachedTeas.put(2, new IcedMilkTea()); cachedTeas.put(3, new IcedLemonTea()); } public Tea make(int type) { return cachedTeas.get(type); } }
一下子清爽了不少,连exchange()函数都直接省了,当然也不难看出,这两种写法都违背了 开闭原则(OCP),如果要添加新产品,需要改动NewTeaStore中的代码。不过实际开发中,用不着那么苛刻,如果不需要频繁的新增产品,稍微不符合开闭原则也是可以接受的。
如果是第一种写法,想去掉if分支逻辑,比较经典的处理方法就是利用 多态,对工厂类抽象一波。
② 工厂方法 (Factory Method)
// 工厂抽象 public interface ITeaStore { Tea createTea(); } // 具体工厂 public class TapiocaMilkTeaStore implements ITeaStore{ @Override public Tea createTea() { return new TapiocaMilkTea(); } } public class HKStyleHotTeaStore implements ITeaStore { @Override public Tea createTea() { return new HKStyleHotTea(); } } public class IcedMilkTeaStore implements ITeaStore { @Override public Tea createTea() { return new IcedMilkTea(); } } public class IcedLemonTeaStore implements ITeaStore{ @Override public Tea createTea() { return new IcedLemonTea(); } } public class NewTeaStore { public Tea make(int type) { String teaName = exchange(type); ITeaStore teaStore = null; if (teaName.equals("珍珠奶茶")) { teaStore = new TapiocaMilkTeaStore(); } else if (teaName.equals("港式奶茶")) { teaStore = new HKStyleHotTeaStore(); } else if (teaName.equals("冰奶茶")) { teaStore = new IcedMilkTeaStore(); } else if (teaName.equals("冻柠茶")) { teaStore = new IcedLemonTeaStore(); } return teaStore.createTea(); } }
改动后的结果并没有如我们所愿,跟之前一样耦合,没解决问题反倒使得设计变得更复杂了,一个解决问题的思路就是:为工厂类再创建一个简单工厂,即工厂的工厂,用来创建工厂类对象。
public class TeaStoreFactoryMap { private static final Map<Integer, ITeaStore> cachedTeaStores = new HashMap<>(); static { cachedTeaStores.put(0, new TapiocaMilkTeaStore()); cachedTeaStores.put(1, new HKStyleHotTeaStore()); cachedTeaStores.put(2, new IcedMilkTeaStore()); cachedTeaStores.put(3, new IcedLemonTeaStore()); } public static Tea make(int type) { return cachedTeaStores.get(type).createTea(); } } // 调用处直接 TeaStoreFactoryMap.make(new Random().nextInt(5));
添加新的解析规则,只需创建新的Tea类和TeaStore类,然后将新的TeaStore实例加入到TeaStoreFactoryMap的cachedTeaStores中即可,代码改动非常少,基本符合开闭原则。
不过,在这个简单的场景里,工厂方法模式无疑增加了代码的繁杂性,有点过度设计的味道了,而且每个TeaStore类只是new操作,所以此处用简单工厂模式更佳。
当对象创建逻辑比较复杂,不只是new一下,还要组合其他类做各种初始化操作时,推荐使用工厂方法模式,将复杂的逻辑创建拆分到多个工厂类,让每个工厂类不至于太过复杂。
强调一点:复杂度是无法被消除的
,只能被转移,比如上面的if-else,用map后从你的 可视范围
内消除了,实际上是转移到map的get逻辑里了。
③ 抽象工厂 (Abstract Factory)
抽象工厂平时很少用,适用场景:创建的对象有多个相互关联或依赖的产品族,定义:提供了一个用于创建相关或相关对象族的接口,而无须指定其具体类。
说下产品族:同一工厂生产, 位于不同产品等级结构
的一组产品。看不懂?没关系,拆词,显示产品等级结构,举下例子:
Tea是父类,珍珠奶茶、港式奶茶等是子类,这就构成一个产品等级结构;
再举一个例子:
Snack小吃是父类,手抓饼、章鱼小丸子是子类,也构成一个产品等级结构;
Tea和Snack位于不同的产品等级结构,然后是一组产品,怎么理解:
奶茶店现在不卖单品了,卖套餐,茶饮搭配小吃。
此时再看会抽象工厂的适用场景,就不难理解了,抽象工厂由四个角色组成:
- 抽象工厂:声明一组用于创建产品族的方法,每个方法对应一种产品;
- 抽象产品:为每种产品声明接口,声明产品所具有的业务方法;
- 具体工厂:实现抽象工厂创建产品的方法,生成具体的产品;
- 具体产品:抽象产品的具体化,实现方法并进行扩展;