大话设计模式--第一章 简单工厂设计模式

简介: 简单工厂设计模式

简单工厂设计模式


案例: 写一个计算器, 实现加减乘除.


分析:   1. 有两个数, num1 和 num2.


    2. 有一个操作符


    3. 有一个业务逻辑运算

 

第一步: 拿到这个业务, 我们直观的思考, 可以想象到这个业务非常简单:


package com.designModel.chapter1_simpleFactory.step1;
import java.io.IOException;
import java.util.Scanner;
/**
 * 计算器: 实现两个数的加, 减, 乘, 除
 * 
 * 第一步思路. 输入两个数, 一个运算符. 执行运算
 *
 */
public class Caculator {
    public static void main(String[] args) {
        try {
            String num1;
            String num2; 
            String operate;
            int result = 0;
            System.out.println("输入num1:");
            Scanner scan = new Scanner(System.in);
            num1 = scan.nextLine();
            System.out.println("输入num2:");
            scan = new Scanner(System.in);
            num2 = scan.nextLine();
            System.out.println("输入运算符:");
            scan = new Scanner(System.in);
            operate = scan.nextLine();
            int n1 = Integer.parseInt(num1);
            int n2 = Integer.parseInt(num2);
            switch(operate){
                case "+":
                    result = n1 + n2;
                    break;
                case "-":
                    result = n1 - n2;
                    break;
                case "*":
                    result = n1 * n2;
                    break;
                case "/":
                    result = n1 / n2;
                    break;
            }
            System.out.println("运算结果:" + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 这样操作的问题: 前端输入和后端逻辑运算完全混合在一起. 维护起来及其不方便
     * 那么如果优化, 第一步就是讲前端输入和业务逻辑分开处理
     */
}


分析:


这样操作的问题: 
    前端输入和后端逻辑运算完全混合在一起. 维护起来非常不方便


这里完全没有使用到面向对象的特征. 下面回顾面向对象的特征


1. 可维护性:  程序出现问题了, 方便维护修改, 且不会影响到其他正常的业务逻辑
2. 可复用性: 一段代码可以在多处被使用
3. 可扩展性: 有新的需求, 在不改变原来逻辑的基础上方便的增减
4. 灵活性: 无论是放在哪里, 稍微改变就可实现新的业务逻辑.


从这四个方面考虑. 上面这段代码, 维护性差, 改一个地方很可能或误改正确的地方; 复用性, 除了计算器, 其他地方基本不可用. 扩展性也不好, 添加一个开方, 可能误改加减乘除. 灵活性, 就没有.

 

那么. 如何使用面向对象的方式来修改呢?


第二步. 将业务逻辑和前端页面相分离


package com.designModel.chapter1_simpleFactory.step2;
import java.io.IOException;
import java.util.Scanner;
/**
 * 计算器: 实现两个数的加, 减, 乘, 除
 * 
 * 第一步思路. 输入两个数, 一个运算符. 执行运算
 * --------------------------------------
 * 再上一个案例的基础上, 将前端和后端逻辑分开处理
 * 
 */
public class Caculator {
    public int caculate(int n1, int n2, String operate){
        int result = 0;
        switch(operate){
            case "+":
                result = n1 + n2;
                break;
            case "-":
                result = n1 - n2;
                break;
            case "*":
                result = n1 * n2;
                break;
            case "/":
                result = n1 / n2;
                break;
        }
        return result;
    }
    public static void main(String[] args) {
     //前端输入
        try {
            String num1;
            String num2; 
            String operate;
            int result = 0;
            System.out.println("输入num1:");
            Scanner scan = new Scanner(System.in);
            num1 = scan.nextLine();
            System.out.println("输入num2:");
            scan = new Scanner(System.in);
            num2 = scan.nextLine();
            System.out.println("输入运算符:");
            scan = new Scanner(System.in);
            operate = scan.nextLine();
            int n1 = Integer.parseInt(num1);
            int n2 = Integer.parseInt(num2);
            Caculator c = new Caculator();
            result = c.caculate(n1, n2, operate);
            System.out.println("运算结果:" + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 现在计算逻辑和前端数据处理的逻辑分开了. 可是依然有问题, 问题在哪里呢? 计算业务逻辑将耦合性太强
     * 比如: 我现在要添加一个算法,开平方根. 这时候, 需要在也逻辑处进行修改, 添加一个switch分支. 这是后, 如果业务逻辑大的话, 
     * 很可能会误操作更改了之前已经写好的的业务逻辑.
     * 
     * 例如: 我们的薪资系统
     * 原来只有技术人员(月薪), 销售人员(底薪+提成), 经理(年薪+股份)三种运算方法, 现在要增加兼职工作人员(时薪)的算法.
     * 
     * 按照我们上面的代码逻辑, 公司必须把包含原三种算法的运算累给你, 让你修改. 这是, 如果你有点私心, 小算盘一打, 除了增加时薪外, 
     * 还修改了技术人员的薪资
     *         salary = salary * 1.1;
     * 那就意味着你的月薪会增加10%. 本来是让你加一个功能的, 结果却修改了另一个功能. 这个风险太大了. 
     * 
     * 所以: 我们要改进这种算法. 分离加减乘除, 让其中一个运算修改, 不会影响到另外几个.
     * 这就用到了面向对象的三大特性: 封装, 继承 和 多态.
     * 
     */
}


正如上面代码的总结:


 /**
     * 现在计算逻辑和前端数据处理的逻辑分开了. 可是依然有问题, 问题在哪里呢? 计算业务逻辑将耦合性太强
   *
     * 比如: 我现在要添加一个算法,开平方根. 这时候, 需要在业务逻辑处进行修改, 添加一个switch分支. 这时, 如果业务逻辑大的话, 
     * 很可能会误操作更改了之前已经写好的的业务逻辑.
     * 
     * 例如: 我们的薪资系统
     * 原来只有技术人员(月薪), 销售人员(底薪+提成), 经理(年薪+股份)三种运算方法, 现在要增加兼职工作人员(时薪)的算法.
     * 
     * 按照我们上面的代码逻辑, 公司必须把包含原三种算法的运算类给你, 让你修改. 这时, 如果你有点私心, 小算盘一打, 除了增加时薪外, 
     * 还修改了技术人员的薪资
     *         salary = salary * 1.1;
     * 那就意味着你的月薪会增加10%. 本来是让你加一个功能的, 结果却修改了另一个功能. 这个风险太大了. 
     * 
     * 所以: 我们要改进这种算法. 分离加减乘除, 让其中一个运算修改, 不会影响到另外几个.
   *
     * 这就用到了面向对象的三大特性: 封装, 继承 和 多态.
     * 
     */


第三步:将输入参数封装成对象, 将加减乘除的业务逻辑单独出来一个类,


package com.designModel.chapter1_simpleFactory.step3;
public class Operation {
    private double num1;
    private double num2;
    public double getResult(){
        double result = 0;
        return result;
    }
    public double getNum1() {
        return num1;
    }
    public void setNum1(double num1) {
        this.num1 = num1;
    }
    public double getNum2() {
        return num2;
    }
    public void setNum2(double num2) {
        this.num2 = num2;
    } 
}


package com.designModel.chapter1_simpleFactory.step3.biz;
import com.designModel.chapter1_simpleFactory.step3.Operation;
public class OperationAdd extends Operation{
    @Override
    public double getResult() {
        return super.getNum1() + super.getNum2();
    }
}


package com.designModel.chapter1_simpleFactory.step3.biz;
import com.designModel.chapter1_simpleFactory.step3.Operation;
public class OperationSub extends Operation{
    @Override
    public double getResult() {
        return super.getNum1() - super.getNum2();
    }
}


package com.designModel.chapter1_simpleFactory.step3.biz;
import com.designModel.chapter1_simpleFactory.step3.Operation;
public class OperationMul extends Operation{
    @Override
    public double getResult() {
        return super.getNum1() * super.getNum2();
    }
}


package com.designModel.chapter1_simpleFactory.step3.biz;
import com.designModel.chapter1_simpleFactory.step3.Operation;
public class OperationDiv extends Operation{
    @Override
    public double getResult() {
        if(super.getNum2() == 0){
            try {
                throw new Exception("除数不能为零");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return super.getNum1() / super.getNum2();
    }
}


这时候, 我在增加一个开平方根的算法, 就不会影响到其他四个类的算法了? 那么, 如何让计算器知道我要用那个算法呢?


现在的问题就是如何实例化对象了. ----  简单工厂设计模式.


package com.designModel.chapter1_simpleFactory.step3;
import com.designModel.chapter1_simpleFactory.step3.biz.OperationAdd;
import com.designModel.chapter1_simpleFactory.step3.biz.OperationDiv;
import com.designModel.chapter1_simpleFactory.step3.biz.OperationMul;
import com.designModel.chapter1_simpleFactory.step3.biz.OperationSub;
public class OperationFactory {
    public static Operation createOperate(String operate) {
        Operation ope = null;
        switch(operate){
            case "+":
                ope = new OperationAdd();
                break;
            case "-":
                ope = new OperationSub();
                break;
            case "*":
                ope = new OperationMul();
                break;
            case "/":
                ope = new OperationDiv();
                break;
        }
        return ope;
    }    
}


在使用的时候, 你只需像下面这样操作就可以了.


public static void main(String[] args) {
    Operation ope = new Operation();
    ope = OperationFactory.createOperate("+");
    ope.setNum1(10);
    ope.setNum2(20);
    System.out.println(ope.getResult());
}


使用了工厂设计模式以后, 当你想要增加一个开平方根的算法时, 要怎么做呢?


1. 增加一个开平方根的类继承自Operation.


2. 在工厂中增加一个case分支.


搞定!


一个小小的计算器, 也可以使用算法. 那么我们在使用其他的方式的时候, 更要考虑算法了?


总结:


在实际项目中,简单工厂模式是我们使用的最多的设计模式之一,简单工厂模式在应对需求变更的过程中也起到了很大的作用。

 

使用情景:


       再不确定会有多少个处理操作时应该考虑使用简单工厂模式,如针对同样的接收到的数据,处理的逻辑可能会不同,可能以后还会增加新的操作。 


案例:


  例如如果实现计算器的功能时,对于同样的输入数据,可能执行加、减、乘、除,甚至其他的功能。因此可以抽象出一个操作的抽象类或是接口,提供一个统一的处理方法(此处为process),然后每种操作创建出一个子类出来。而判断具体使用哪个具体的实现类是在工厂类中进行判断的(将存放操作的变量传递给工厂的生产方法)。工厂类始终返回的是这个抽象类,这样如果对原有功能进行更改或是新添加新的功能,也不会对原来的其他类做修改,只编译修改的那个类或是新的类就可以了。


这样就做到了把耦合降到最低,同时也便于维护。


注意:如果客户提出要再添加一个功能来处理这些数据,实现起来就灰常方便了


UML类图


这个计算器类的UML图如下:


微信图片_20220508171054.png


下面来学习一下UML类图的画法


微信图片_20220508171122.png


总结:


空心三角形+实现-->继承


空心三角形+虚线-->实现接口


实线+箭头-->关联关系


徐建+箭头-->依赖关系


实心菱形+实线+箭头-->组合关系


空心菱形+实线+箭头-->聚合关系


简单工厂设计模式, 在项目中, 可以使用的场景

 

1. 支付: 支付有支付宝支付, 微信支付, 还有银联支付. 以后还可能有新的支付方式. 这时候就可以使用简单工厂设计模式.

 

处理方式:

微信图片_20220508171150.png


斜体表示抽象类: 例如Pay类

相关文章
|
9月前
|
设计模式 Java 数据库
小谈设计模式(2)—简单工厂模式
小谈设计模式(2)—简单工厂模式
|
9月前
|
设计模式 Java PHP
php设计模式--简单工厂模式(一)
php设计模式--简单工厂模式(一)
46 0
|
25天前
|
设计模式 关系型数据库
「全网最细 + 实战源码案例」设计模式——简单工厂模式
简单工厂模式是一种创建型设计模式,通过工厂类根据传入参数创建不同类型的对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。适用于对象种类较少且调用者无需关心创建细节的场景。
53 19
|
5月前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
9月前
|
设计模式
设计模式-简单工厂和工厂方法
设计模式-简单工厂和工厂方法
|
6月前
|
设计模式 XML Java
【一】设计模式~~~创建型模式~~~简单工厂模式(Java)
文章详细介绍了简单工厂模式(Simple Factory Pattern),这是一种创建型设计模式,用于根据输入参数的不同返回不同类的实例,而客户端不需要知道具体类名。文章通过图表类的实例,展示了简单工厂模式的结构、时序图、代码实现、优缺点以及适用环境,并提供了Java代码示例和扩展应用,如通过配置文件读取参数来实现对象的创建。
【一】设计模式~~~创建型模式~~~简单工厂模式(Java)
|
6月前
|
设计模式 uml C语言
设计模式----------工厂模式之简单工厂模式(创建型)
这篇文章详细介绍了简单工厂模式,包括其定义、应用场景、UML类图、通用代码实现、运行结果、实际应用例子,以及如何通过反射机制实现对象创建,从而提高代码的扩展性和维护性。
设计模式----------工厂模式之简单工厂模式(创建型)
|
6月前
|
设计模式 测试技术 Go
[设计模式]创建型模式-简单工厂模式
[设计模式]创建型模式-简单工厂模式
|
8月前
|
设计模式 Java
Java设计模式:工厂模式之简单工厂、工厂方法、抽象工厂(三)
Java设计模式:工厂模式之简单工厂、工厂方法、抽象工厂(三)
|
8月前
|
设计模式 Java 编译器
设计模式——创建型模式(工厂,简单工厂,单例,建造者,原型)
设计模式——创建型模式(工厂,简单工厂,单例,建造者,原型)

热门文章

最新文章