本意是想像美剧的previously那样, 不知道怎么翻译好, 求翻译达人赐教...
上集讲到, 小光辞了工作, 开起了热干面的店子, 用Builder模式改造了热干面的构建过程, 是日渐稳定有效起来, 生意也是越来越好.
但是小光是善于观察的同学啊, 他发现热干面真的好干啊(好像一般人也都能发现, 鬼脸~). 心想, 解决用户痛点才产品的存在根本啊, 是时候推出新东西了.
于是他决定跟推出自己的光氏饮料产品.
经过一番调查和走访, 小光发现几个特点:
于是, 小光选用了最新的XX牌 (有广告商找我吗? 哈哈.) 速溶饮料. 制作饮料的过程很简单, 很快, 小光做出了第一杯饮料---橙汁:
- public class OrangeJuice {
-
- public void make() {
- // 1. 拿出一次性饮料杯
- System.out.println("拿出一次性饮料杯");
-
- // 2. 加入速溶橙汁粉
- System.out.println("加入速溶橙汁粉");
-
- // 3. 加水冲兑
- System.out.println("加水");
-
- // 4. 加盖, 打包
- System.out.println("加盖, 打包");
- }
- }
-
看起来, 程序似乎是可以运转了, 让我们投入生产吧...
然而, 小光何许人啊, 毕竟是在码农界混了好些年的同志啊. 还没有投入使用, 就发现了"问题":
饮料有很多种, 过程都类似, 只是放的速溶包不一样. 如果我每个都这么写, 改天真有人找我打广告, 杯子上印个二维码什么的, 我不是每个饮料的制作过程都要改啊
灵光一现, 小光想起了面向对象思想中提到的抽象, 封装, 于是乎, 小光改写了自己的程序:
他抽象出来一个"Drink"类:
- public abstract class Drink {
-
- public void make() {
- // 1. 拿出一次性饮料杯
- System.out.println("拿出一次性饮料杯");
-
- // 2. 加入速溶橙汁粉
- System.out.println("加入" + getInstantPackage());
-
- // 3. 加水冲兑
- System.out.println("加水");
-
- // 4. 加盖, 打包
- System.out.println("加盖, 打包");
- }
-
- abstract String getInstantPackage();
- }
-
可乐, 酸梅汤, 橙汁皆继承了Drink:
- public class Coke extends Drink {
- @Override
- String getInstantPackage() {
- return "速溶可乐粉";
- }
- }
-
- public class PlumJuice extends Drink {
- @Override
- String getInstantPackage() {
- return "速溶酸梅粉";
- }
- }
-
- public class OrangeJuice extends Drink {
- @Override
- String getInstantPackage() {
- return "速溶橙汁粉";
- }
- }
-
制作完饮料, 准备开卖了, 是这样的:
- public class XiaoGuang {
-
- public static void main(String[] args) {
-
- OrangeJuice orangeJuice = new OrangeJuice();
- orangeJuice.make();
- }
- }
-
第二天, 生意实在太好, 小光请了表妹临时来帮忙泡制饮料. 而且, 小光还发现自己也无需关注用户要什么饮料了, 直接让用户告诉表妹, 表妹直接制作饮料给用户就行~
表妹负责根据用户要求生产饮料:
- public class Cousins {
-
- public static Drink create(String drinkType) {
-
- // Java7开始, switch支持String
- switch (drinkType) {
- case "橙汁":
- return new OrangeJuice();
-
- case "酸梅汤":
- return new PlumJuice();
-
- case "可乐":
- return new Coke();
-
- default:
- return new OrangeJuice();
- }
- }
- }
-
小光不再关注饮料具体种类:
- public class XiaoGuang {
-
- public static void main(String[] args) {
-
- Drink drink = Cousins.create("可乐");
- drink.make();
- }
- }
-
加上饮料套餐之后, 生意果然越来越好, 估计也有美女助阵的加成, 哈哈...
可能有些同学已经看出一点熟悉感了, 我们把这些关系一个UML表示下:
如此, 应该就比较清晰了, 这个就是我们今天的主题---简单工厂.
严格来说, 简单工厂并非一种设计模式, 可以说是一种编码习惯.
那么我们为什么要使用简单工厂, 或者说这么做有什么好处呢?
从我们这个例子中, 可以看到, 小光(Client类)不需要去关注饮料泡制(Drink make)这个过程了, 有更多的时间去接待客户, 只需从表妹(工厂类)那拿到相应的饮料给客户即可.
这个其实是蕴含了单一职责的编程思想:
简单工厂一般来说, 使用一个静态方法来生产产品, 故而有时也称之为静态工厂方法模式.
在这个故事的过程中, 我们提到了面向对象的抽象, 封装特性. 实际上我们所有的OOD原则, 设计模式, 都是基于面向对象的思想的, 离不开抽象, 封装, 继承, 多态几大特性. 随着对这些设计模式的分析, 也可以让我们加深面向对象的编程思想.
以Glide为例, 其中的DefaultConnectivityMonitorFactory.java就是一个类似的简单工厂实现:
- public class DefaultConnectivityMonitorFactory implements ConnectivityMonitorFactory {
-
- @NonNull
- public ConnectivityMonitor build(
- @NonNull Context context,
- @NonNull ConnectivityMonitor.ConnectivityListener listener) {
- final int res = context.checkCallingOrSelfPermission("android.permission.ACCESS_NETWORK_STATE");
- final boolean hasPermission = res == PackageManager.PERMISSION_GRANTED;
- if (hasPermission) {
- return new DefaultConnectivityMonitor(context, listener);
- } else {
- return new NullConnectivityMonitor();
- }
- }
- }
-
与表妹Cousins(工厂)的实现很类似, 只是这个Factory具体创建什么产品不是由传入的参数决定的, 是在内部的逻辑决定的.
转化为类图关系, 更加清晰:
一直在说的话: 所谓架构, 设计模式都是一种思想, 没有固定的招式, 所有的这些招式都是让我们入门, 了解面向对象的基础思想, 然后能运用无形. 共勉.
大家可能有发现, 简单工厂的弊端也是很多的, 表妹(工厂)的责任太重, 包含(UML依赖关系)了所有的具体产品的实现. 另外, 如果需要修改或增加产品, 我们就得改变工厂类的实现. 这显然违反了开闭原则.
故而, 简单工厂, 一般来说, 适用于产品类别较少, 且固定的场景.