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


    人物:大鸟,小菜

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


     工厂方法模式:

    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是保持了封装对象创建过程中的优点(即使要更换对象,不需要做大的改动就可以实现,降低了客户程序和产品对象的耦合),但是还是没有解决客户端判断的问题啊?

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

  • 相关阅读:
    SQL创建索引
    SQLServer最耗资源时间的SQL语句
    C# Linq删除父级的同时删除子级
    C# 根据类名创建类的实例对象
    C#利用反射实现两个类的对象之间相同属性的值的复制
    linq时间筛选以及list时间筛选
    为什么watch机制不是银弹?
    我们的前端模版引擎更新总结
    小矮人Javascript模块加载器
    Javascript模版引擎简介
  • 原文地址:https://www.cnblogs.com/wencheng9012/p/13387247.html
Copyright © 2020-2023  润新知