大话设计模式——简单工厂模式

面向过程

需求:使用Java实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果。

1)简单实现

public static void version1() {
    
    
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入数字A:");
        int A = scanner.nextInt();
        System.out.println("请输入数字B:");
        int B = scanner.nextInt();
        System.out.println("请输入运算符号(+、-、*、/):");
        String oper = scanner.next();
        int result = 0;
        if (oper.equals("+")) {
    
     // 问题1:分支判断写法不好,计算机做了3次无用功
            result = A + B;
        }
        if (oper.equals("-")) {
    
    
            result = A - B;
        }
        if (oper.equals("*")) {
    
    
            result = A * B;
        }
        if (oper.equals("/")) {
    
    
            result = A / B; // 问题2:如果除数时输入0如何处理,输入的是字符符号不是数字如何处理
        }
        System.out.println("结果是:" + result);
    }

存在的问题:

  1. 分支判断的写法不好,使计算机做了3次无用功
  2. 如果除数时输入0如何处理?输入的是字符符号不是数字如何处理?

2)改进

  1. 使用switch进行分支改造
  2. 增加了除数判断,增加了try…catch
 public static void version2() {
    
    
        try {
    
    
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入数字A:");
            int A = scanner.nextInt();
            System.out.println("请输入数字B:");
            int B = scanner.nextInt();
            System.out.println("请输入运算符号(+、-、*、/):");
            String oper = scanner.next();
            int result = 0;
            switch (oper) {
    
    
            case "+":
                result = A + B;
                break;
            case "-":
                result = A - B;
                break;
            case "*":
                result = A * B;
                break;
            case "/":
                if (B != 0) {
    
    
                    result = A / B;
                } else {
    
    
                    throw new IllegalArgumentException("除数不能为0");
                }
                break;
            }
            System.out.println("结果是:" + result);
        } catch (Exception e) {
    
    
            System.out.println("您的输入有误:" + e.getMessage());
        }
    }

上述只是实现功能,但其实是用计算机的方式去思考。比如程序要求输入两个数和运算符号,然后根据运算符号判断选择如何运算,得到结果,这本身没有错。但这样的思维却使得我们的程序只为满足实现当前的需求,程序不容易【维护】,不容易【扩展】,更不容易【复用】,从而达不到高质量的要求。

面向对象

需求:要求再写一个Windows的计算器,上述的代码能否复用呢?

1)简单实现

当代码中重复的代码多到一定程度的时候,维护的时候可能就是一场灾难。 越大的系统问题越严重,编程有一原则,用尽可能的办法去避免重复,考虑哪些是和计算器有关的,哪些是和控制台无关的。让业务逻辑与界面逻辑分开,让它们之间的耦合度下降。

/**
 * 运算类(Operation):
 * 在Windows程序、Web版程序、PDA、手机等需要移动系统的软件需要运算都可以用它。
 */
public class Operation {
    
    
    public static double getResult(double A, double B, String operate) {
    
    
        double result = 0d;
        switch (operate) {
    
    
        case "+":
            result = A + B;
            break;
        case "-":
            result = A - B;
            break;
        case "*":
            result = A * B;
            break;
        case "/":
            result = A / B;
            break;
        }
        return result;
    }
}

客户端代码:

    public static void main(String[] args) {
    
    
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入数字A:");
        int A = scanner.nextInt();
        System.out.println("请输入数字B:");
        int B = scanner.nextInt();
        System.out.println("请输入运算符号(+、-、*、/):");
        String oper = scanner.next();
        double result = Operation.getResult(A, B, oper);
        System.out.println("结果是:"+result);
    }

2)改进

问:如果我希望增加一个开根运算,如何修改?
答:只需要改Operation类就行了,在switch中加一个分支就行了。

问题是要加一个平方根运算,却需要让加减乘除的运算都参与编译,如果不小心将加法改成了减法,岂不是很糟糕。本来让你加一个功能,却让运行良好的功能代码发生了变化,这个风险太大了。所以应该将加减乘除等运算分离,修改其中要给不影响另外的几个,增加运算算法也不影响其他代码

public abstract class Operation {
    
    
    private double numberA = 0;
    private double numberB = 0;
    
    /**
     * 子类实现运算操作
     */
    public abstract double getResult();

    public double getNumberA() {
    
    
        return numberA;
    }

    public void setNumberA(double numberA) {
    
    
        this.numberA = numberA;
    }

    public double getNumberB() {
    
    
        return numberB;
    }

    public void setNumberB(double numberB) {
    
    
        this.numberB = numberB;
    }
}
// 加
public class OperationAdd extends Operation {
    
    
    @Override
    public double getResult() {
    
    
        return getNumberA() + getNumberB();
    }
}
// 减
public class OperationSub extends Operation {
    
    
    @Override
    public double getResult() {
    
    
        return getNumberA() - getNumberB();
    }
}
// 乘
public class OperationMul extends Operation {
    
    
    @Override
    public double getResult() {
    
    
        return getNumberA() * getNumberB();
    }
}
// 除
public class OperationDiv extends Operation {
    
    
    @Override
    public double getResult() {
    
    
        if (getNumberB() == 0) {
    
    
            throw new IllegalArgumentException("除数不能为0");
        }
        return getNumberA() / getNumberB();
    }
}

3)简单工厂模式

如何让计算器知道我希望使用哪一种算法呢?使用简单工厂模式。
到底要实例化谁,将来会不会增加实例化的对象,比如增加开根运算,
这是很容易变化的地方,应该考虑用一个单独的类来做这个创造实例的过程,这就是工厂。

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

客户端类:
只需要输入运算符号,工厂就实例化出合适的对象,通过多态,返回父类的方式实现了计算器的结果
如果要修改:1:增加运算子类 2:在工厂类中增加switch分支

 public static void main(String[] args) {
    
    
    Operation oper= OperationFactory.createOperate("+");
    oper.setNumberA(1);
    oper.setNumberB(2);
    double result = oper.getResult();
    System.out.println(result);
}

猜你喜欢

转载自blog.csdn.net/fengsheng5210/article/details/123965979
今日推荐