【设计模式】 (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);

    }
}

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

posted @ 2020-01-15 17:52  IT猿看视界  阅读(143)  评论(0编辑  收藏  举报