大话设计模式读书笔记(工厂方法模式)

人物:大鸟,小菜

事件:小菜找大鸟聊天,大鸟了解到小菜同学薛磊风因车祸,腿受伤住院,小菜去医院探望他时发现,薛磊风几年以来一直帮助一个孤寡老人,为老人洗衣扫地,买米买油,现在因为出了意外不能帮助老人了,所以薛磊风委托小菜和同学们在这段时间里,帮忙照顾老人


 工厂方法模式:

1.回顾简单工厂模式

2.了解工厂方法模式

3.分析简单工厂模式和工厂方法模式的区别,提出工厂方法模式的缺点

4.通过结合学雷锋做好事的案例,做出雷锋工厂,分析了工厂方法模式的优点,然后解释清楚了第3点提出的所谓的缺点,并说明这个“缺点”在后续会用其他方式解决

回顾简单工厂模式

工厂类实现:

public class OperationFactory {
    public static Operation createOperate(String operate) {
        Operation oper = null;
        switch (operate) {
            case "+":
                oper = new OperationAdd();
            case "-":
                //oper = new OperationSub();
            case "*":
                //oper = new OperationMul();
            case "/":
                //oper = new OperationDiv();
                break;
        }
        return oper;
    }
}

客户端的应用:

public static void main(String[] args) {
    Operation oper;
    oper = OperationFactory.createOperate("+");
    oper.setNumberA(new BigDecimal("1"));
    oper.setNumberB(new BigDecimal("2"));
    String  result = oper.getResult();
    log.info("运算结果为:{}", result);
}

工厂方法模式实现

工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到子类

具体实现:

先构建一个工厂接口

public interface IFactory {
    Operation createOperation();
}

然后加减乘除各建一个具体工厂去实现这个接口

public class AddFactory implements IFactory {
    @Override
    public Operation createOperation() {
        return new OperationAdd();
    }
}
public class SubFactory implements IFactory {
    @Override
    public Operation createOperation() {
        return new OperationSub();
    }
}
......

客户端实现:

public static void main(String[] args) {
    IFactory operFactory = new AddFactory();
    Operation oper = operFactory.createOperation();
    oper.setNumberA(new BigDecimal("1"));
    oper.setNumberB(new BigDecimal("2"));
    String result = oper.getResult();
    log.info("result:{}", result);
}

小菜:关于简单工厂模式和工厂方法模式,我还是有疑问,新加一个开根号的功能,需要修改的代码部分如下,工厂方法模式这不就比简单工厂模式更复杂了么?

简单工厂模式 工厂方法模式
1.先加一个开根号的功能类 1.加功能类
2.然后去加工厂方法,在里面的Case里面加开根号的逻辑 2.加工厂类
  3.改客户端代码

 

 

 

 

 

大鸟:是的,这也就是简单工厂模式和工厂方法模式的区别所在

简单工厂模式

1.最大优点:是在工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态地实例化相关的类,对于客户端来说,去除了与具体产品的依赖

2.例如:像计算器,把"+"传给工厂,工厂自动实例出对象,客户端只要做运算即可

3.缺点:这里的问题在于,要增加一个开根号的功能,要去修改"Case"里的逻辑,所以不仅对扩展开放了,而且对修改也开放了,违反了开放-封闭原则

工厂方法模式

1.优点:因为将实例化对象延迟到了子类中进行,所以新加功能只要增加子类和工厂即可,满足开放-封闭原则

2.小菜对工厂方法模式的疑惑:因为工厂方法模式的实现,客户端需要决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在的,也就是说把以前"Case"的内容从工厂类移到了客户端,这不还是没有解决么???

大鸟:那我们带着问题,再来看雷锋做好事的例子

 

雷锋工厂之简单工厂模式的实现

雷锋类:

@Slf4j
public class LeiFeng {
    public void sweep() {
        log.info("扫地");
    }
    public void wash() {
        log.info("洗衣");
    }
    public void bugRice() {
        log.info("买米");
    }
}

学雷锋的大学生:

public class UnderGraduate extends LeiFeng {
}

学雷锋的社区志愿者:

public class Volunteer extends LeiFeng {
}

简单工厂类:

public class SimpleFactory {
    public static LeiFeng createLeiFeng(String type) {
        LeiFeng result = null;
        switch (type) {
            case "学雷锋的大学生":
                result = new UnderGraduate();
                break;
            case "社区志愿者":
                result = new Volunteer();
                break;
        }
        return result;
    }
}

客户端代码:(这里可以看到分别实例化的时候,三段代码重复了)

public static void main(String[] args) {
    LeiFeng studentA = SimpleFactory.createLeiFeng("学雷锋的大学生");
    studentA.bugRice();
    LeiFeng studentB = SimpleFactory.createLeiFeng("学雷锋的大学生");
    studentB.sweep();
    LeiFeng studentC = SimpleFactory.createLeiFeng("学雷锋的大学生");
    studentC.wash();
    }

雷锋工厂之工厂方法模式的实现

雷锋工厂接口:

public interface LeiFengFactory {
    LeiFeng createLeiFeng();
}

学雷锋的大学生工厂:

public class UnderGraduateFactory implements LeiFengFactory {
    @Override
    public LeiFeng createLeiFeng() {
        return new UnderGraduate();
    }
}

学雷锋的社区志愿者工厂:

public class UnderGraduateFactory implements LeiFengFactory {
    @Override
    public LeiFeng createLeiFeng() {
        return new UnderGraduate();
    }
}

客户端:

public static void main(String[] args) {
    LeiFengFactory factory = new UnderGraduateFactory();
    //要换成社区志愿者,改这一句就行 LeiFengFactory factory = new VolunteerFactory();
    LeiFeng student = factory.createLeiFeng();

    student.bugRice();
    student.sweep();
    student.wash();
}

大鸟:这里可以看出,如果要修改客户端,将学习雷锋的大学生换成学习雷锋的社区志愿者,只用修改这一处就行,而简单工厂模式要改三句

小菜:我知道了,工厂方法模式,1是克服了简单工厂模式违反的开放封闭原则,2是保持了封装对象创建过程中的优点(即使要更换对象,不需要做大的改动就可以实现,降低了客户程序和产品对象的耦合),但是还是没有解决客户端判断的问题啊?

大鸟:别急,利用"反射",可以解决这个问题,这个我们后面慢慢道来

原文地址:https://www.cnblogs.com/wencheng9012/p/13387247.html