设计模式之简单工厂模式与策略模式(通过两种模式设计的计算器/java)(代码片段)

没谱的曲 没谱的曲     2022-12-08     129

关键词:

前言

在前段时间制作的图书馆管理系统的mysql重构版时,通过使用三层架构和面向对象的思维让我对这方面的知识有所提升。但在结束之后经过点拨发现在整个项目重构的过程中没有使用到设计模式里的思想,导致整个项目不太符合低耦合高内聚设计原则。所以决定在学习设计模式后,进行一个简单的小项目来练习使用设计模式。本次选择了简单工厂模式、策略模式以及两个模式混合使用来完成计算器的功能。

简单工厂模式

在百度百科我们可以直接搜索到简单工厂模式的简介:
在这里插入图片描述
由此我们可以得知,使用简单工厂模式设计的项目中,客户端只需要输入相应的内容,就可以通过工厂类来决定需要实例化的对象,通过多态,返回父类的方式实现结果。
通过这样的设计,不管最后使用的是何种程序,都可以通过这串代码实现已经写好的需要的功能。

简单工厂模式设计的计算器

Operation类:

package SimpleFactory.Operation;

public class Operation 
    private double numA = 0;
    private double numB = 0;

    public double getNumA() 
        return numA;
    

    public void setNumA(double numA) 
        this.numA = numA;
    

    public double getNumB() 
        return numB;
    

    public void setNumB(double numB) 
        this.numB = numB;
    

    public double getResult() throws Exception 
        return 0.0;
    

加法类:

package SimpleFactory.Operation;
//加法运算类继承父类Operation类
public class OperationAdd extends Operation
    @Override
    public double getResult() 
        return getNumA()+getNumB();
    


减法类:

package SimpleFactory.Operation;

//减法运算类继承父类Operation类
public class OperationSub extends Operation
    @Override
    public double getResult() 
        return getNumA()-getNumB();
    

乘法类:

package SimpleFactory.Operation;

//乘法运算类继承父类Operation类
public class OperationMul extends Operation
    @Override
    public double getResult() 
        return getNumA()*getNumB();
    

除法类:

package SimpleFactory.Operation;
//除法运算类继承父类Operation类
public class OperationDiv extends Operation
    @Override
    public double getResult() throws Exception 
        if (getNumB() == 0)
            throw new Exception("除数不能为0!");
        
        return getNumA()/getNumB();
    

工厂类:

package SimpleFactory.Operation;

//简单工厂类
//只要输入运算符号,工厂就实例化出合适的对象,通过多态,返回父类的方式实现了计算器的结果
public class OperationFactory
    private Operation operation;
    public Operation simpleFactory (String type)
        switch (type)
            case "+":
                operation = new OperationAdd();
                break;
            case "-":
                operation = new OperationSub();
                break;
            case "*":
                operation = new OperationMul();
                break;
            case "/":
                operation = new OperationDiv();
                break;
        
        return operation;
    


最后到了客户端的代码类(Calculator类):

import java.util.Scanner;

public class Calculator 

    public static void main(String[] args) throws Exception 

        Operation operation;
        OperationFactory operationFactory = new OperationFactory();
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入第一个数字:");
        double numA = scanner.nextDouble();
        System.out.println("请输入运算符号:");
        String type = scanner.next();
        System.out.println("请输入第二个数字:");
        double numB = scanner.nextDouble();
        operation = operationFactory.simpleFactory(type);
        operation.setNumA(numA);
        operation.setNumB(numB);
        double result = operation.getResult();
        System.out.println("结果 = "+result);
        /**
         * 以下部分为实现重复运算的代码,做测试使用
         */
//        boolean flag = true;
//        while (flag)
//            System.out.println("请输入运算符号(+、-、*、/;输入其他字符退出运算):");
//            String type1 = scanner.next();
//            if (!type1.equals("+")&&!type1.equals("-")&&!type1.equals("*")&&!type1.equals("/"))
//                flag=false;
//            else 
//                System.out.println("请输入第二个数字:");
//                double num2 = scanner.nextDouble();
//                operation = operationFactory.simpleFactory(type1);
//                operation.setNumA(result);
//                operation.setNumB(num2);
//                double result1 = operation.getResult();
//                System.out.println("结果 = "+result1);
//                result = result1;
//            
//        
    

运算结果:
在这里插入图片描述
当工厂类负责创建的对象比较少,却客户只知道传入工厂类的参数 ,对于如何创建对象的逻辑不关心时,简单工厂模式使用会非常的方便。
但当系统中具体产品类不断增多的时候,可能会出现要求工厂类更具不同条件创建不同实例的需求,这种条件的判断和对具体产品类型的判断交错在一起的时候,简单工厂类就很难避免模块功能的蔓延,对系统的维护和扩展非常不利。这时候就需要我们用到其他的一些设计模式了。

策略模式

在百度百科上,我们同样可以很快的找到策略模式的简介:
在这里插入图片描述
简单来说,策略模式定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。

通过策略模式来实现计算器

Strategy类(策略类):

package Strategy;

//定义所有支持的算法的公共接口
//定义的抽象类或接口Strategy,每一个算法类都要实现这个抽象类下的抽象方法(或接口)
public abstract class Strategy 
    public abstract double strategy(double numA,double numB) throws Exception;


加法类:

package Strategy;

//加法类,继承自策略类Strategy,实现了抽象方法,实现加法运算
public class AddStrategy extends Strategy

    @Override
    public double strategy(double numA, double numB) throws Exception 
        return numA+numB;
    


减法类:

package Strategy;

//减法类,继承自策略类Strategy,实现了抽象方法,实现减法运算
public class SubStrategy extends Strategy

    @Override
    public double strategy(double numA, double numB) throws Exception 
        return numA-numB;
    

乘法类:

package Strategy;

//乘法类,继承自策略类Strategy,实现了抽象方法,实现乘法运算
public class MulStrategy extends Strategy

    @Override
    public double strategy(double numA, double numB)  throws Exception
        return numA*numB;
    


除法类:

package Strategy;

//除法类,继承自策略类Strategy,实现了抽象方法,实现除法运算
public class DivStrategy extends Strategy

    @Override
    public double strategy(double numA, double numB) throws Exception 
        if (numB == 0) 
            throw new Exception("除数不能为0!");
        
        return numA/numB;
    


Context类:

package Strategy;

//Context上下文,用一个ConcreteStrategy来配置,维护一个队Strategy对象的引用
public class Context 
    private Strategy strategy;

    public Context(Strategy strategy)
        this.strategy = strategy;
    

    public double getResult(double numA, double numB) throws Exception 
        return strategy.strategy(numA,numB);
    


客户端代码(Client类):

package Strategy;

import java.util.Scanner;

public class Client 
    public static void main(String[] args) throws Exception 
        Context context = null;
        Scanner scanner = new Scanner(System.in);
        double result;
        String type;
        double numA;
        double numB;
        System.out.println("请输入第一个数字:");
        numA = scanner.nextDouble();
        System.out.println("请输入运算符号:");
        type = scanner.next();
        System.out.println("请输入第二个数字:");
        numB = scanner.nextDouble();
//        context.setStrategy(new AddStrategy());
        switch (type) 
            case "+":
                context = new Context(new AddStrategy());
                break;
            case "-":
                context = new Context(new SubStrategy());
                break;
            case "*":
                context = new Context(new MulStrategy());
                break;
            case "/":
                context = new Context(new DivStrategy());
                break;
        
        result = context.getResult(numA, numB);
        System.out.println("结果=" + result);

    



运行结果:
在这里插入图片描述
当多个类之区别在表现的行为是不同的时候,可以使用策略模式,在运行时动态的选择要具体执行的行为。策略模式可以对客户隐藏具体算法的实现细节,彼此完全独立。
但是,客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
这时候,我们可以使用策略加简单工厂的方式来实现

策略模式加简单工厂模式

通过上面对简单工厂模式和策略模式的运用,我们可以得知:

  1. 使用简单工厂模式的时候,客户只知道传入工厂类的参数,对于如何创建对象无需关心;
  2. 策略模式需要客户端知道所有的算法或行为。

那么,我们为什么不将两种模式结合一下,让用户不需要了解如何创建对象,就可以选择恰当的算法呢?

策略模式加简单工厂模式设计的计算器

基于以上信息,我们只需要在前面策略模式设计的计算器上再加上一个简单工厂就可以解决这个问题。

我们将Context类中的构造方法设计成一个工厂,具体代码如下:

public Context(String type)
        switch (type)
            case "+":
                AddStrategy add = new AddStrategy();
                strategy = add;
                break;
            case "-":
                SubStrategy sub = new SubStrategy();
                strategy = sub;
                break;
            case "*":
                MulStrategy mul = new MulStrategy();
                strategy = mul;
                break;
            case "/":
                DivStrategy div = new DivStrategy();
                strategy = div;
                break;
        
    

完成后的Context类:

package Strategy;

//Context上下文,用一个ConcreteStrategy来配置,维护一个队Strategy对象的引用
public class Context 
    private Strategy strategy;

    public Context(String type)
        switch (type)
            case "+":
                AddStrategy add = new AddStrategy();
                strategy = add;
                break;
            case "-":
                SubStrategy sub = new SubStrategy();
                strategy = sub;
                break;
            case "*":
                MulStrategy mul = new MulStrategy();
                strategy = mul;
                break;
            case "/":
                DivStrategy div = new DivStrategy();
                strategy = div;
                break;
        
    

    public double getResult(double numA, double numB) throws Exception 
        return strategy.strategy(numA,numB);
    


客户端代码(StrategyAndFactoryClient类):

package Strategy;

import java.util.Scanner;

public class StrategyAndFactoryClient 
    public static void main(String[] args) throws Exception 
        Context context = null;
        double result;
        Scanner scanner = new Scanner(System.in);
        String type;
        double numA;
        double numB;
        System.out.println("请输入第一个数字:");
        numA = scanner.nextDouble();
        System.out.println("请输入运算符号:");
        type = scanner.next();
        System.out.println("请输入第二个数字:");
        numB = scanner.nextDouble();
        context = new Context(type);
        result = context.getResult(numA,numB);
        System.out.println(result);

    

运行结果:
在这里插入图片描述

这时我们可以看到,我们只需要在客户端输入相应的运算符号,就可以在构造方法(工厂)中进行判断,根据传入的参数,动态决定应该创建哪一个对象,解决了使用策略模式时客户需要自己来决定创建哪一个对象的问题。

总结

学习设计模式是一个很漫长的过程,往往我们需要花费大量的时间才能将其融会贯通,在使用的时候才能得心应手,要想达到这样的境界就需要在这个过程中进行大量的练习,才能在使用的时候得心应手。路漫漫其修远兮,吾将上下而求索。

设计模式之简单工厂模式与策略模式(通过两种模式设计的计算器/java)(代码片段)

...束之后经过点拨发现在整个项目重构的过程中没有使用到设计模式里的思想,导致整个项目不太符合低耦合高内聚设计原则。所以决定在学习设计模式后,进行一个简单的小项目来练习使用设计模式。本次选择了简单工... 查看详情

设计模式之策略模式&简单工厂模式

  学习设计模式已经有非常长一段时间了。事实上先前已经敲过一遍了,可是老认为没有学到什么,认识也不够深刻,如今趁着重构机房。再又一次来过,也不晚。 事实上在敲了机房之后,看看模式,事实上。曾经非... 查看详情

设计模式之策略模式&简单工厂模式

  学习设计模式已经有非常长一段时间了,事实上先前已经敲过一遍了。可是老认为没有学到什么,认识也不够深刻。如今趁着重构机房,再又一次来过,也不晚。 事实上在敲了机房之后,看看模式,事实上,曾经非... 查看详情

设计模式之简单工厂模式(代码片段)

引言   所属:创建型模式,常用设计模式之一  工厂模式分为:简单工厂模式、工厂方法模式、静态工厂模式、抽象工厂模式。  下面为简单工厂模式。 工厂模式概述   通过使用一个公共接口来指向不同方... 查看详情

设计模式:简单工厂工厂方法抽象工厂之小结与区别

简单工厂,工厂方法,抽象工厂都属于设计模式中的创建型模式。其主要功能都是帮助我们把对象的实例化部分抽取了出来,优化了系统的架构,并且增强了系统的扩展性。本文是本人对这三种模式学习后的一个小结以及对他们... 查看详情

设计模式java工厂模式与应用(代码片段)

...对静态工厂进行简单的介绍。并介绍与实现其与其他两种设计模式——单例模式与享元模式,的组合实现,以达到特定的功能实现。文章目录Java工厂模式与应用摘要一.简单工厂模式简介二.简单工厂模式三.静态工厂模式&... 查看详情

设计模式之工厂模式-简单工厂(02)

设计模式分创建型、行为型、结构型;工厂模式属于创建型模式,分(1)简单工厂(静态工厂)(2)工厂方法(3)抽象工厂,下面分别通过代码来介绍(本篇文章北风网的视频看后写的);(一)简单工厂  简单工厂描述:... 查看详情

设计模式之简单工厂模式(代码片段)

简单来说,工厂模式就是按照需求来返回一个类型的对象,使用工厂模式的意义就是,如果对象的实例化与代码依赖太大的话,不方便进行扩展和维护,使用工厂的目的就是使对象的实例化与主程序代码就行解耦.1.简单工厂模式简介简... 查看详情

34面向对象设计模式之工厂模式——简单工厂模式与工厂方法模式比较(代码片段)

用下面的例子比较:  usingSystem;namespaceLearnObjectpublicclassLeiFengpublicvoidSweep()Console.WriteLine("扫地");publicvoidWash()Console.WriteLine("洗衣服");publicvoidBuyRice()Console.WriteLine("买米");publi 查看详情

设计模式:简单工厂模式

   介绍简单工厂模式之前先通过一个披萨项目的例子来引出问题,然后给出简单工厂模式这种解决方案,然后随着披萨项目的不断扩展,遇到新的问题,引出工厂方法模式,然后又遇到新的问题,引出最终解决方案,... 查看详情

设计模式之简单工厂模式

设计模式之简单工厂模式动机:        不暴露实例化逻辑来创建对象。通过公共的接口创建新的对象。        这是一个简单的实现,客户端需要一个product,但是client不... 查看详情

编程学习之简单工厂模式与策略模式

...老师说写代码要考虑重构,架构,在此期间学习到了一种简单工厂模式。何为简单工厂模式呢?简单工厂模式又叫静态工厂方法模式(StaticFactoryMethodPattern),是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都... 查看详情

设计模式学习笔记之简单工厂模式

 简介:工厂模式(FactoryPattern)是Java中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,拒绝客服端程序员通... 查看详情

设计模式之抽象工厂模式

前两章我们已经讨论了两种有关工厂的模式,今天我们来看最后一种与工厂相关的模式,抽象工厂模式。            抽象工厂模式算是工厂相关模式的终极形态,如果各位完全理解了上... 查看详情

设计模式之工厂模式(代码片段)

工厂模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。简单工厂模式与工厂模式区别:  (1)简单工厂模式的优点在于工厂类中包含了必要的逻辑判断,根据客户... 查看详情

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

简单工厂模式  最近朋友推荐了一本书《大话设计模式》,此书刚刚到,博主也还没开始看,希望以博文的方式与大家一起分享,一起学习.简单工厂模式,也就是说,到底要实列化谁,将来会不会增加实列化的对象,比如增加开根运算,... 查看详情

工厂模式策略者模式责任链模式综合应用(代码片段)

设计模式的具体运用:  简单工厂模式、策略者模式、责任链模式定义与使用classLoader的具体运用  自定义的classloader来动态加载类程序功能设计:  在商城购物时,商城可能会在特殊的日子、或者依据会员等级,对结算... 查看详情

设计模式之简单工厂模式(代码片段)

简单工厂模式简单工厂模式的主要实现思路是通过一个工厂类实例化需求所需的功能类,这样做可以增加代码的可拓展性,降低耦合性。1、创建抽象类,规范子类中需要定义的方法(抽象类中的方法在子类中必须被定义)1<?ph... 查看详情