设计模式--简单工厂

154 阅读4分钟

被老公埋汰

媳妇儿由于一直做业务系统的开发,所以技术方面已经跟不上时代潮流了。今天就被老公狠狠地羞辱了一番。

起因

媳妇儿的业务需要实现一个计算器控制程序。

package design01;
import java.util.Scanner;
public class Test01 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入数字A: ");
        String A = sc.nextLine();
        System.out.print("请输入运算符号(+、-、*、/): ");
        String B = sc.nextLine();
        System.out.print("请输入数字B: ");
        String C = sc.nextLine();
        String D = "";
        if (B.equals("+")) {
            D = String.valueOf(Integer.parseInt(A) + Integer.parseInt(C));
        } else if (B.equals("-")) {
            D = String.valueOf(Integer.parseInt(A) - Integer.parseInt(C));
        } else if (B.equals("*")) {
            D = String.valueOf(Integer.parseInt(A) * Integer.parseInt(C));
        } else if (B.equals("/")) {
            D = String.valueOf(Integer.parseInt(A) / Integer.parseInt(C));
        } else {
            System.out.println("运算符号输入错误!");
            
        }
        System.out.println("结果是: " + D);

    }
}

问题解析

20240909-210222.jpg

有错就改,媳妇美德

基于以上问题,媳妇儿重构了一下代码,如下:

package design01;
import java.util.Scanner;
public class Test01 {
    public static void main(String[] args) {
        try {
            System.out.println("请输入数字A: ");
            Scanner sc = new Scanner(System.in);
            String strNumberA = sc.nextLine();
            System.out.println("请输入运算符号(+、-、*、/): ");
            String strOperate = sc.nextLine();
            System.out.println("请输入数字B: ");
            String strNumberB = sc.nextLine();
            String result = "";
            switch (strOperate) {
                case "+":
                    result = String.valueOf(Integer.parseInt(strNumberA) + Integer.parseInt(strNumberB));
                    break;
                case "-":
                    result = String.valueOf(Integer.parseInt(strNumberA) - Integer.parseInt(strNumberB));
                    break;
                case "*":
                    result = String.valueOf(Integer.parseInt(strNumberA) * Integer.parseInt(strNumberB));
                    break;
                case "/":
                    if (Integer.parseInt(strNumberB) == 0) {
                        System.out.println("除数不能为0!");
                        return;
                    } else {
                        result = String.valueOf(Integer.parseInt(strNumberA) / Integer.parseInt(strNumberB));
                    }
                    break;
            }
            System.out.println("结果是:" + result);
        } catch (Exception ex) {
            System.out.println("您的输入有错:" + ex.getMessage());
        }
    }
}

信心满满的让老公看,结果又被老公教育了一番。既然用了java代码,就要用面向对象编程。

面向对象

教育媳妇儿:面向过程和面向对象的区别。面向过程是以计算机能够理解的逻辑来解决问题,第一步做什么、第二步做什么......,这样写出来的代码不容易维护和扩展。

好处

  • 传统印刷术:将所有文字刻在同一个面板上,耦合度太高,如果改其中的一个字,则整个面板都需要重新刻制
  • 活字印刷术:每个字都单独刻制,需要修改哪个字就改那个字,活刻活用

业务封装

界面逻辑和业务逻辑分开,让他们的耦合度降低 媳妇儿吭哧瘪肚重新修改一版代码,如下

操作类封装

public class Operation {
    public static double getResult(double strNumberA, double strNumberB, String operate) {
        double result = 0d;
        switch (operate) {
            case "+":
                result = strNumberA + strNumberB;
                break;
            case "-":
                result = strNumberA - strNumberB;
                break;
            case "*":
                result = strNumberA * strNumberB;
                break;
            case "/":
                result = strNumberA / strNumberB;
                break;
        }
        return result;
    }
}

客户端类封装

import java.util.Scanner;

public class Test01 {
    public static void main(String[] args) {
        try {
            System.out.println("请输入数字A: ");
            Scanner sc = new Scanner(System.in);
            String strNumberA = sc.nextLine();
            System.out.println("请输入运算符号(+、-、*、/): ");
            String strOperate = sc.nextLine();
            System.out.println("请输入数字B: ");
            String strNumberB = sc.nextLine();
            String result = "";
            result = String.valueOf(Operation.getResult(Double.parseDouble(strNumberA), Double.parseDouble(strNumberB), strOperate));
            System.out.println("结果是:" + result);
        } catch (Exception ex) {
            System.out.println("您的输入有错:" + ex.getMessage());
        }
    }
}

紧耦合/松耦合

媳妇儿:现在界面显示和客户端已经分离,是不是很灵活了 老公:还差的远,现在操作是在一个类中实现的,如果要增加一个开根号算法,怎么弄? 媳妇儿:那还不简单,增加一个判断不就可以了。 老公:有一个开闭原则知道么?面向修改关闭,面向增加开放。再想想怎么通过继承,将Operation类解耦。 媳妇冥思苦想,终于有办法。

修改代码如下:

/**
 * 操作抽象类
 */
public abstract class Operation {
    private double numberA = 0;
    private double numberB = 0;
    public Operation(double numberA, double numberB) {
        this.numberA = numberA;
        this.numberB = numberB;
    }
    public double getNumberA() {
        return numberA;
    }
    public double getNumberB() {
        return numberB;
    }
    abstract double getResult();
}

/**
 * 加法操作类
 */
public class OperationAdd extends Operation {
    public OperationAdd(double numberA, double numberB) {
        super(numberA, numberB);
    }

    @Override
    public double getResult() {
        return super.getNumberA() + super.getNumberB();
    }
    
}

/**
 * 除法操作类
 */
public class OperationDiv extends Operation {
    public OperationDiv(double numberA, double numberB) {
        super(numberA, numberB);
    }

    @Override
    public double getResult() {
        if (super.getNumberB() == 0) {
            throw new IllegalArgumentException("The divisor cannot be zero.");
        }
        return super.getNumberA() / super.getNumberB();
    }
}

/**
 * 乘法操作类
 */
public class OperationMul extends Operation {
    public OperationMul(double numberA, double numberB) {
        super(numberA, numberB);
    }

    @Override
    public double getResult() {
        return super.getNumberA() * super.getNumberB();
    }
}

/**
 * 减法操作类
 */
public class OperationSub extends Operation {
    public OperationSub(double numberA, double numberB) {
        super(numberA, numberB);
    }

    @Override
    public double getResult() {
        return super.getNumberA() - super.getNumberB();
    }
    
}

如上代码将操作完全解耦了。增加开平方,只需要增加一个继承Operation类就可以实现了。

简单工厂模式

老公:挺不错,现在的问题是如何实例化对象了。告诉你一个简单工厂模式,也就是说,到底要实例化谁。

代码如下:

public class OperationFactory {
    public static Operation createOperation(String operation, double numberA, double numberB) {
        Operation oper = null;
        switch (operation) {
            case "+":
                oper = new OperationAdd(numberA, numberB);
                break;
            case "-":
                oper = new OperationSub(numberA, numberB);
                break;
            case "*":
                oper = new OperationMul(numberA, numberB);
                break;
            case "/":
                oper = new OperationDiv(numberA, numberB);
                break;
        }
        return oper;
    }
}

测试代码:

public class Test01 {
    public static void main(String[] args) {
        Operation oper = OperationFactory.createOperation("+", 1, 2);
        System.out.println(oper.getResult());
        oper = OperationFactory.createOperation("*", 1, 2);
        System.out.println(oper.getResult());
    }
}

总结

简单工厂模式(Simple Factory Pattern)是一种常用的软件设计模式,属于创建型模式之一。它提供了一个创建对象的静态方法,而不必将客户端代码与对象创建过程耦合起来。简单工厂的核心是一个工厂类,该类包含一个静态方法用于实例化产品类的对象,客户端通过传递一个参数来决定创建哪一个具体的产品对象。此模式简化了客户端代码,使其不需要关心具体产品的创建逻辑,但当系统中添加新的产品时,需要修改工厂类,这违背了开闭原则。此外,随着产品类型的增多,工厂类会变得庞大且难以维护。简单工厂模式适用于产品族较少且产品类的公共接口已知的情况。