zoukankan      html  css  js  c++  java
  • 【设计模式】 (5) 工厂模式

    工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
    在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

    工厂模式介绍(来自菜鸟教程)

    意图:
    定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

    主要解决:
    主要解决接口选择的问题。

    何时使用:
    我们明确地计划不同条件下创建不同实例时。

    如何解决:
    让其子类实现工厂接口,返回的也是一个抽象的产品。

    关键代码:
    创建过程在其子类执行。

    **应用实例: **
    1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。
    2、Hibernate 换数据库只需换方言和驱动就可以。

    优点:
    1、一个调用者想创建一个对象,只要知道其名称就可以了。
    2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
    3、屏蔽产品的具体实现,调用者只关心产品的接口。

    缺点:
    每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

    使用场景:
    1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
    2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。

    注意事项:
    作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

    工厂模式实战

    老夫在参加校招的时候,忘了是哪个公司,先参加笔试,笔试内容是 Java/C 任意选择一个开发语言作为我们笔试的基本语言。因为老夫对 C 向来没兴趣,就选择了 Java . 在笔试题中 , 有一道题目是使用 面向对象语言 Java 编写一个可实现 加 / 减 / 乘 / 除 基本功能的简易计算器。这看起来还是很简单的。所以老夫就随手写了,按照顺序写的,就跟 C 一样。

    public class Calculator {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in) ;
            while (true){
                System.out.println("请输入数字 A : ");
                int numA = scanner.nextInt();
                System.out.println("输入操作符: ");
                String operator = scanner.next();
                System.out.println("输入数字 B : ");
                int numB = scanner.nextInt();
    
                int result = operate(numA, operator, numB);
    
                System.out.println("计算后的结果为: " + result);
            }
        }
    
        public static int operate(int numA , String operator , int numB){
            switch (operator){
                case "+" :
                    return (numA + numB) ;
                case "-":
                    return (numA - numB) ;
                case "*":
                    return (numA * numB) ;
                case "/":
                    if (numB == 0){
                        throw new IllegalArgumentException("除数不可为 0") ;
                    }else {
                        return (numA / numB) ;
                    }
                default:
                    throw new IllegalArgumentException("nothing ... ") ;
            }
        }
    }
    

    后来,面试官拿到我的笔试题,前面的都没看,看到我的程序,就问我,你觉得你的程序有什么问题?然后我说,功能都没问题呀,好像没啥别的毛病。面试官跟我说:“你的功能是实现了,但是你有没有看到要求。用面向对象语言 Java 来实现,你实现了这个功能,但面向对象没有体现出来。你觉得怎么去改它。”后来面试官应该看不下去了,就跟我说:“简单点,你把这个业务代码和这个界面分离,这个你能做到吧。”后来我改成了下面的这个:

    public class Calculator {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in) ;
            while (true){
                System.out.println("请输入数字 A : ");
                int numA = scanner.nextInt();
                System.out.println("输入操作符: ");
                String operator = scanner.next();
                System.out.println("输入数字 B : ");
                int numB = scanner.nextInt();
    
                int result = Operator.operate(numA, operator, numB);
    
                System.out.println("计算后的结果为: " + result);
            }
        }
    
        
    }
    
    class Operator{
        public static int operate(int numA , String operator , int numB){
            switch (operator){
                case "+" :
                    return (numA + numB) ;
                case "-":
                    return (numA - numB) ;
                case "*":
                    return (numA * numB) ;
                case "/":
                    if (numB == 0){
                        throw new IllegalArgumentException("除数不可为 0") ;
                    }else {
                        return (numA / numB) ;
                    }
                default:
                    throw new IllegalArgumentException("nothing ... ") ;
            }
        }
    }
    

    然后他跟我说:“你这样写,不就分开了吗。”后来我们就聊了下入职实习等一些情况。讲真的,当时我是真没觉得这有啥子区别,我就换个位置而已。后来才知道,分开之后相当于解耦的过程。上述的过程其实相当于一个封装的过程。将操作部分封装在一个类里面。

    工厂模式下的调整

    首先,我们先将上面的程序在重构一下,上面的耦合性太高,再解耦。
    这是新的 Operator.java

    public abstract class Operator {
        public int numA ;
        public int numB ;
    
    
        public int getNumA() {
            return numA;
        }
    
        public void setNumA(int numA) {
            this.numA = numA;
        }
    
        public int getNumB() {
            return numB;
        }
    
        public void setNumB(int numB) {
            this.numB = numB;
        }
    
        public abstract int getResult();
    }
    
    

    OperatorAdd.java

    public class OperatorAdd extends Operator {
    
        @Override
        public int getResult() {
            return numA + numB;
        }
    }
    

    OperatorFactory.java

    public class OperatorFactory {
    
        public static Operator createOperatorFactory(String operate){
            switch (operate){
                case "+" :
                    return new OperatorAdd() ;
                case "-":
                    return new OperatorSub() ;
                case "*":
                    return new OperatorMul() ;
                case "/":
                    return new OperatorDiv() ;
                default:
                    throw new IllegalArgumentException("Are you kidding ? ") ;
            }
        }
    }
    

    在工厂类中,OperatorSub.java , OperatorMul.java , OperatorDiv.java 与 OperatorAdd.java 相似。

    现在再看主类:

    public class Calculator {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in) ;
    
            System.out.println("请输入数字 A : ");
            int numA = scanner.nextInt();
            System.out.println("输入操作符: ");
            String operate = scanner.next();
            System.out.println("输入数字 B : ");
            int numB = scanner.nextInt();
    
            Operator operator = OperatorFactory.createOperatorFactory(operate) ;
            operator.setNumA(numA);
            operator.setNumB(numB);
            int result = operator.getResult();
            System.out.println(result);
    
        }
    }
    

    以上便是一个很简单的工厂模式。

  • 相关阅读:
    Redis设计与实现第一部分:第5章:Redis 跳跃表
    根据临时表修改主表的某字段数据根据主表的主键
    Redis设计与实现第一部分:第2章:简单动态字符串SDS
    Redis
    MySQL的访问控制与用户管理
    MySQL字符集和语言的基础知识
    生成日志文件
    Python进阶09 动态类型
    Python进阶08 异常处理
    Python进阶07 函数对象
  • 原文地址:https://www.cnblogs.com/sun-iot/p/12198015.html
Copyright © 2011-2022 走看看