工厂设计模式

工厂设计模式


简介

​ 工厂设计模式是最常见的设计模式之一,在工厂模式中,提供一种最佳的创建对象的方式,最大程度的实现代码的解耦

  1. 什么是工厂模式? 通过一个工厂类创建类似功能的不同实现类的父类或接口,不用关注你所获取的类是怎么实现的,只要通过工厂获取到对象即可使用
  2. 工厂模式需要的三大模块:
    • 一个父类或者一个接口:定义该功能的方法、属性
    • 一个实现类或者子类:实现或者继承上面的接口或者父类
    • 工厂类:通过工厂类获取实现类的父类或者接口(这里用到的多态)
  3. 优点:
    • 扩展性高:当你想增加一个产品,只需要扩展工厂类,并增加一个产品即可
    • 使用简单:屏蔽了产品的具体实现,使用者只用关注产品的接口即可
    • 高度解耦
  4. 缺点:

    • 每次增加一个产品的时候都需要新增一个实现类,这样下来类的数量不断增加,增加了系统 复杂度

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

具体实现

例:输入两个数字和 + - * / 符号,实现加减乘除算法

初步实现:

public static void main(String[] args) {
        boolean boo = true;
        while (boo){
            String next = "";
            int a = 0;
            int b = 0;
            try {
                System.out.println("请输入第一个数字:");
                Scanner scanner = new Scanner(System.in);
                a = scanner.nextInt();
                System.out.println("请输入:+ - * / 四个符号");
                Scanner scanner2 = new Scanner(System.in);
                next = scanner2.next();
                System.out.println("请输入第二个数字:");
                Scanner scanner1 = new Scanner(System.in);
                b = scanner1.nextInt();
                System.out.println("结果是:");
            }catch (Exception e){
                System.out.println("输入有误!!!");
                e.printStackTrace();
            }
            switch (next){
                case "+" :
                    System.out.println(a + b);
                    break;
                case "-" :
                    System.out.println(a-b);
                    break;
                case "*" :
                    System.out.println(a*b);
                    break;
                case "/" :
                    if (b==0){
                        System.out.println("除数不能为0");
                        break;
                    }
                    System.out.println(a/b);
                    break;
                default:
                    System.out.println("符号有误");
            }
            System.out.println("是否关闭计算器?Y/N");
            Scanner close = new Scanner(System.in);
            String isClose = close.next();
            if ("Y".equals(isClose)){
                boo = false;
            }
        }
    }

这样写完全可以实现了我们的加减乘除操作,但是却不利于维护,比如当我们有其他地方也需要只用这个算法的时候我们就只能把switch代码copy一份去使用,造成代码冗余,而以后随着业务的不断增加可能还需要新增“开根”、“平方”等操作,如果我们在多个地方都这样写,可想而知我们需要改多少地方

那么有人会说,直接把switch代码封装起来,在其他地方调用就行了,无论需要怎么改我们只用修改这块代码即可。这样我们的代码就非常容易维护了

初步改造:

public static void main(String[] args) {
        boolean boo = true;
        while (boo){
            String next = "";
            int a = 0;
            int b = 0;
            try {
                System.out.println("请输入第一个数字:");
                Scanner scanner = new Scanner(System.in);
                a = scanner.nextInt();
                System.out.println("请输入:+ - * / 四个符号");
                Scanner scanner2 = new Scanner(System.in);
                next = scanner2.next();
                System.out.println("请输入第二个数字:");
                Scanner scanner1 = new Scanner(System.in);
                b = scanner1.nextInt();
                System.out.println("结果是:");
            }catch (Exception e){
                System.out.println("输入有误!!!");
                e.printStackTrace();
            }
            getResult(next, a, b);
            System.out.println("是否关闭计算器?Y/N");
            Scanner close = new Scanner(System.in);
            String isClose = close.next();
            if ("Y".equals(isClose)){
                boo = false;
            }
        }
    }

    private static void getResult(String next, int a, int b) {
        switch (next){
            case "+" :
                System.out.println(a + b);
                break;
            case "-" :
                System.out.println(a-b);
                break;
            case "*" :
                System.out.println(a*b);
                break;
            case "/" :
                if (b==0){
                    System.out.println("除数不能为0");
                    break;
                }
                System.out.println(a/b);
                break;
            default:
                System.out.println("符号有误");
        }
    }

经过这次的改造,我们的代码看着似乎已经非常棒了,可以很方便的修改算法,而且无论怎么改动我们只需要修改getResult方法即可

问题:所有算法全都暴露出来,当我们修改的时候不可避免的会触碰到原来好的代码,那么我们怎么样才能做到各个功能,不同算法之间完全独立呢?

解决:这个时候我们就需要用到工厂了

工厂模式下的加减乘除:

算法接口

public interface Algorithm {
    public int getResult(int a,int b);
}

实现算法接口,不同的算法

public class Add implements Algorithm {
    @Override
    public int getResult(int a,int b) {
        int sum = a + b;
        return sum;
    }
}
public class Sub implements Algorithm {
    @Override
    public int getResult(int a, int b) {
        int sub = a - b;
        return sub;
    }
}
public class Mul implements Algorithm {
    @Override
    public int getResult(int a,int b) {
        return a*b;
    }
}
public class Division implements Algorithm {
    @Override
    public int getResult(int a,int b) {
        if (b == 0){
            throw new RuntimeException("除数不能为0");
        }
        return a/b;
    }
}

这样加减乘除的算法已经实现。那么我们在使用的时候需要创建不同的算法对象,等于在使用的时候还是暴露的直接的类,那么我们的定义的接口在这里只是起到了一个规范的作用,那么我们怎么才能不关注具体实现呢?或者说我们怎么才最大化的解耦

解决:使用面向接口编程

工厂类:通过工厂获取不同算法的实现(这里用到了多态)

public class ComputeFactory {

    public static Algorithm getAlgorithm(String symbol){
        switch (symbol){
            case "+":
                return new Add();
            case "-":
                return new Sub();
            case "*":
                return new Mul();
            case "/":
                return new Division();
            default:
                throw new RuntimeException("符号有误!!!");
        }
    }
}

现在我们可以直接从这里获取算法,我们只关注接口就行了,不用关注下面的算法怎么实现的,这样我们就最大程度的实现了功能的解耦

现在再看一下我们的最终的代码,工厂类、接口、实现类,这就是一个完整的工厂模式,接下来我们来使用的时候就非常方便了

public static void main(String[] args) {
        boolean boo = true;
        while (boo){
            System.out.println("请输入第一个数字:");
            Scanner scannerA = new Scanner(System.in);
            int a = scannerA.nextInt();
            System.out.println("请输入:+ - * / 四个符号");
            Scanner scanner = new Scanner(System.in);
            String next = scanner.next();
            System.out.println("请输入第二个数字:");
            Scanner scannerB = new Scanner(System.in);
            int b = scannerB.nextInt();
            System.out.println("结果是:");
            Algorithm algorithm = ComputeFactory.getAlgorithm(next);
            int result = algorithm.getResult(a,b);
            System.out.println(result);
            System.out.println("是否关闭计算器?Y/N");
            Scanner close = new Scanner(System.in);
            String isClose = close.next();
            if ("Y".equals(isClose)){
                boo = false;
            }
        }

这样我们在以后如果想再添加一个算法,或者修改一个算法的时候只用新增一个独立的类或者就该某一个类的算法就行了,完全不存在影响其他算法的情况