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

简单工厂模式

面向对象和面向过程

在大话设计模式中,为了引出简单工厂模式这一个话题,作者举了一个计算器的例子,通过不断的去优化计算器功能的实现代码,来帮助我们理解面向对象这一概念。

  1. 首先是初始的代码,逻辑简单明了,是面向过程的方法去解决的,用计算机的方式去思考问题,直接判断输入的符号,再进行相应的运算。对于简单的程序而言,这样做的好处就是直观,效率高。但是以这样的逻辑去编写的代码存在一个较大的缺陷,那就是局限性太大,只能满足当前的需求,当需求发生变化的时候,我们就需要再主函数中进行相应的修改,当需求复杂的时候,代码非常多,这样所有的逻辑写在一起,光看起来就费劲,万一改动的时候不小心改变了其它部分的代码,很容易出现问题,而且难以排查;除此之外,这样写的代码也没法复用,当我在其它地方使用时,还得把代码复制一份。
//面向过程c#
class Program {
    static void Main(string[] args) {
        try {
            Console.Write("请输入数字A:");
            string strNumberA = Console.ReadLine();
            Console.Write("请选择运算符号(+、-、*、/):");
            string strOperate = Console.ReadLine();
            Console.Write("请输入数字B:");
            string strNumberB = Console.ReadLine();
            string strResult = "";
            switch (strOperate) {
                case "+":
                    strResult =
                            Convert.ToString(Convert.ToDouble(strNumberA)
                                    + Convert.ToDouble(strNumberB));
                    break;
                case "-":
                    strResult = Convert.ToString(Convert.ToDouble(strNumberA) - Convert.ToDouble(strNumberB));
                    break;
                case "*":
                    strResult = Convert.ToString(Convert.ToDouble(strNumberA) * Convert.ToDouble(strNumberB));
                    break;
                case "/":
                    if (strNumberB != "0")
                        strResult = Convert.ToString(Convert.ToDouble(strNumberA) / Convert.ToDouble(strNumberB));
                    else
                        strResult = "除数不能为0";
                    break;
            }
            Console.WriteLine("结果是:" + strResult);
            Console.ReadLine();
        } catch (Exception ex) {
            Console.WriteLine("您的输入有错:" + ex.Message);
        }
    }
}
  1. 在讲到面向对象时,作者在文中举了一个非常形象的例子,那就是活字印刷:为每个字都做一个刻板,在印刷不同的文章时,只需更改字的顺序,在出现没印刷过的字时或者出现某个字刻错了的情况,只需要为这个字制作一个新的刻板,其它字的刻板照常使用。面向对象的优点就在于其通过封装、继承和多态的方式,让代码“分工明确,各司其职”,它将负责不同业务的代码分离,相互之间互不影响,这样做既解决了问题复杂时的代码冗余问题,又能够将刻好的“字”复用到其他地方。这样就做到了代码的易维护,易扩展和可复用。

public class Operation {
    private double numberA = 0;
    private double numberB = 0;

    public Operation() {
    }

    public Operation(double numberA, double numberB) {
        this.numberA = numberA;
        this.numberB = numberB;
    }

    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 double getResult() {
        return 0D;
    }
}

public class OperationAdd extends Operation {
    public OperationAdd() {
    }

    public OperationAdd(double numberA, double numberB) {
        super(numberA, numberB);
    }

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

public class OperationDel extends Operation {
    public OperationDel() {
    }

    public OperationDel(double numberA, double numberB) {
        super(numberA, numberB);
    }

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

public class OperationDiv extends Operation {
    public OperationDiv() {
    }

    public OperationDiv(double numberA, double numberB) {
        super(numberA, numberB);
    }

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

public class OperationMul extends Operation {
    public OperationMul() {
    }

    public OperationMul(double numberA, double numberB) {
        super(numberA, numberB);
    }

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

  1. 上述代码定义了一个父类和四个子类,父类中可以存放一些公共的东西,比如操作数;然后在子类中重写父类的GetResult方法,不同的符号有着不同的运算逻辑,这样我们需要增加或者修改业务逻辑时,就只需要增加子类,或者修改其中某个子类,而不会影响到其它子类的使用,并且写好的子类可以在其他位置多次调用。调用方式如下所示:
import java.util.Scanner;

/**
 * @Author yirui
 * @Date 2024/4/9 10:26
 * @Version 1.0
 */
public class Program {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        try {
            System.out.println("请输入数字A:");
            Double strNumberA = sc.nextDouble();
            sc.nextLine(); // 清除换行符
            System.out.println("请选择运算符号(+、-、*、/):");
            String strOperate = sc.nextLine();
            System.out.println("请输入数字B:");
            Double strNumberB = sc.nextDouble();
            String strResult = "";
            Operation operation;
            switch (strOperate) {
                case "+":
                    operation = new OperationAdd(strNumberA, strNumberB);
                    strResult = String.valueOf(operation.getResult());
                    break;
                case "-":
                    operation = new OperationDel(strNumberA, strNumberB);
                    strResult = String.valueOf(operation.getResult());
                    break;
                case "*":
                    operation = new OperationMul(strNumberA, strNumberB);
                    strResult = String.valueOf(operation.getResult());
                    break;
                case "/":
                    if (strNumberB != 0D) {
                        operation = new OperationDiv(strNumberA, strNumberB);
                        strResult = String.valueOf(operation.getResult());
                        break;
                    } else {
                        strResult = "除数不能为0";
                    }
                    break;
            }
            System.out.println("结果是:" + strResult);
        } catch (Exception ex) {
            System.out.println("您的输入有错:" + ex.toString());
        } finally {
            sc.close();
        }
    }
}

简单工厂模式

上述计算器的计算过程虽然通过父子类之间的继承做到了易扩展,易维护和可复用,但是最后进行调用的代码任然过于复杂,我们只是把运算的业务逻辑分离出去了,而根据运算符去判断创建哪个对象的业务逻辑代码仍然和界面代码(从用户那儿获取数据的代码)放在一块,这样我们在新增一种运算规则的时候,仍然需要修改这里面的业务逻辑,仍然不够方便。在实际的开发过程中,我们应该尽可能的把界面逻辑和业务逻辑分离开,降低他们之间的耦合度,这样才能够真正的做到易维护和易扩展,于是作者就引出了简单工厂模式。

  1. 所谓“工厂”,就是专门生产东西的地方,而在Java中,就是生产对象的地方,我们的四个子类都与运算相关,那我们就可以制造一个运算工厂,专门来为我们创建与运算有关的对象,这样做的好处就是:在我们用户看来,我不需要关心你这个“东西”具体的生产过程,我只需要把材料给你,然后你把结果给我。
public class OperationFactory {
    public static Operation createOperation(Double strNumberA, Double strNumberB,String strOperate) throws Exception{
        Operation operation = null;
        switch (strOperate) {
            case "+":
                operation = new OperationAdd(strNumberA,strNumberB);
                break;
            case "-":
                operation = new OperationDel(strNumberA,strNumberB);
                break;
            case "*":
                operation = new OperationMul(strNumberA,strNumberB);
                break;
            case "/":
                if (strNumberB != 0D){
                    operation = new OperationDiv(strNumberA,strNumberB);
                    break;
                } else {
                    throw new Exception("除数不能为0!");
                }
        }
        return operation;
    }
}
  1. 有了这个工厂之后,客户端的代码就变成了这样,以后即使新增了计算规则,我们也只需要新增子类,并且修改工厂类中的业务逻辑,而客户端的代码只专注于界面逻辑(改改提示信息或者界面即可),不包含业务逻辑相关的修改。
import java.util.Scanner;

/**
 * @Author yirui
 * @Date 2024/4/9 11:18
 * @Version 1.0
 */
public class Program2 {
    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
        try {
        System.out.println("请输入数字A:");
        Double strNumberA = sc.nextDouble();
        sc.nextLine();//清除回车符
        System.out.println("请选择运算符号(+、-、*、/):");
        String strOperate = sc.nextLine();
        System.out.println("请输入数字B:");
        Double strNumberB = sc.nextDouble();
        String strResult = "";
        Operation operation = OperationFactory.createOperation(strNumberA,strNumberB,strOperate);
        strResult = String.valueOf(operation.getResult());
        System.out.println("结果是:" + strResult);
    } catch (Exception ex) {
        System.out.println("您的输入有错:" + ex.toString());
    } finally {
        sc.close();
    }
}
}

总结

面向对象和面向过程的区别

以我的浅薄理解,他们的区别大致可以分为三个方面:思路不同,特点不同和优势不同

  • 面向过程的思路是以过程为核心关注解决一个问题的具体实施流程是什么样的,按照流程去编写函数,一步一步实现最终的目标,它的优点是对于不复杂的问题实现效率高,但是面对复杂的问题时,流程可能会非常繁琐,维护起来会很困难。

  • 而面向对象的思路则是以对象为核心关注一个问题中有哪些角色或者可以分为哪几块功能,每个角色或者每个功能模块只关注自己具有哪些属性和功能,将这些角色或者模块封装成一个一个的对象,通过调用对象的方法或者属性解决最终的问题;面向对象的设计思路相较于面向过程而言可能会更加繁琐,但是当面对较为复杂的问题时,面向对象的方法可以将问题拆分的更加清楚,维护起来更加简单;并且具有高度的扩展性和复用性。

为什么要用简单工厂模式

简单工厂模式是一种创建型设计模式,其本质在于对对象创建过程的抽象。它的作用和优点主要可以概括如下:

  • 分离对象创建使用的职责
    在不使用简单工厂模式时,客户端代码需要直接创建对象,这可能涉及到一连串的代码来构造对象。对象的创建逻辑和界面逻辑混合在一起,不方便管理。
    使用简单工厂模式,我们将对象创建的具体逻辑隐藏起来,交给工厂类来管理。这样,客户端只需知道具体产品类所对应的参数,而无需关心对象的实例化过程。这种分离可以减少代码量,提高代码的可读性和可维护性
  • 灵活性和扩展性
    当业务场景发生变化时,我们可以通过引入配置文件或其他方式,在不修改客户端代码的情况下更换和增加新的具体产品类。
    如果需要增加一种类型的产品,只需修改工厂类中的操作代码,而不需要修改客户端代码。这提高了系统的灵活性和可扩展性。
    总之,简单工厂模式有助于将对象创建的过程抽象出来,使代码更易于维护和扩展。它适用于需要多态性的场景,同时也可以用于减少代码侵入性的情况。
  • 31
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值