02-策略模式学习【策略和简单工厂的组合使用】

写在前面

⭐️大三在校生发发,随时欢迎欢迎大家来交流!

今天学习的是策略模式(Strategy Pattern),依然是参照《大话设计模式》这本书来写的

一、什么是策略模式

  • 策略这个词应该怎么理解,打个比方说,我们出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略。

  • 再比如我们去逛商场,商场现在正在搞活动,有打折的、有满减的、有返利的等等,其实不管商场如何进行促销,说到底都是一些算法,这些算法本身只是一种策略,并且这些算法是随时都可能互相替换的,比如针对同一件商品,今天打八折、明天满100减30,这些策略间是可以互换的。

介绍

**意图:**定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。

**主要解决:**在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。

**何时使用:**一个系统有许多许多类,而区分它们的只是他们直接的行为。

**如何解决:**将这些算法封装成一个一个的类,任意地替换。

**关键代码:**实现同一个接口。

应用实例:

扫描二维码关注公众号,回复: 17471422 查看本文章

1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。

2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。

3、JAVA AWT 中的 LayoutManager。

优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。

缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。

使用场景:

1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。

2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

**注意事项:**如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。

image-20220305220401813

二、需求描述及实现

实现一个超时收银系统,可以进行打折,满一定金额进行返利操作等,也就是商场促销活动

需要提前说明,我这个是是使用了简单工厂模式和策略模式的组合形式【因为单独使用,效果并不完美,其实组合了也不太完美】

创建CashSuper接口

package com.fafa.designmode.strategy;

/**
 * 金额接口
 *
 * @author Sire
 * @version 1.0
 * @date 2022-03-05 18:13
 */
public interface CashSuper {
    
    
    /**
     * 收取金额
     *
     * @param money
     * @return
     */
    double acceptCash(double money);
}

正常收费实现类CashNormal

package com.fafa.designmode.strategy.impl;

import com.fafa.designmode.strategy.CashSuper;

/**
 * 正常收取
 *
 * @author Sire
 * @version 1.0
 * @date 2022-03-05 18:16
 */
public class CashNormal implements CashSuper {
    
    
    @Override
    public double acceptCash(double money) {
    
    
        return money;
    }
}

打折收费实现类CashRebate

package com.fafa.designmode.strategy.impl;

import com.fafa.designmode.strategy.CashSuper;

/**
 * 打折收费
 *
 * @author Sire
 * @version 1.0
 * @date 2022-03-05 18:17
 */
public class CashRebate implements CashSuper {
    
    
    /**
     * 折扣数
     */
    private double moneyRebate = 1D;

    /**
     * 初始化
     *
     * @param moneyRebate
     */
    public CashRebate(double moneyRebate) {
    
    
        this.moneyRebate = moneyRebate;
    }

    @Override
    public double acceptCash(double money) {
    
    
        return money * this.moneyRebate;
    }
}

满一定金额进行返利CashReturn

package com.fafa.designmode.strategy.impl;

import com.fafa.designmode.strategy.CashSuper;

/**
 * 返利收费
 *
 * @author Sire
 * @version 1.0
 * @date 2022-03-05 18:23
 */
public class CashReturn implements CashSuper {
    
    
    /**
     * 返利需要达到的金额
     */
    private double moneyCondition = 0.0D;
    /**
     * 返利金额
     */
    private double moneyReturn = 0.0D;

    public CashReturn(double moneyCondition, double moneyReturn) {
    
    
        this.moneyCondition = moneyCondition;
        this.moneyReturn = moneyReturn;
    }

    @Override
    public double acceptCash(double money) {
    
    
        if (money >= moneyCondition) {
    
    
            // 注意这里按照倍数进行的返利
            // 【Java Math.floor() 方法可对一个数进行下舍入,返回给定参数最大的整数,简称 地板取整】
            money -= Math.floor(money / moneyCondition) * moneyReturn;
        }
        return money;
    }
}

创建策略配置类(上下文)CashContext

package com.fafa.designmode.strategy;

import com.fafa.designmode.strategy.impl.CashNormal;
import com.fafa.designmode.strategy.impl.CashRebate;
import com.fafa.designmode.strategy.impl.CashReturn;

/**
 * 策略配置
 *
 * @author Sire
 * @version 1.0
 * @date 2022-03-05 18:29
 */
public class CashContext {
    
    

    private CashSuper cashSuper;

    /**
     * 注意这里是 策略模式 和 简单工厂模式的结合使用
     * 其实这一层原来是写在了客户端的,所以运用结合的方式,将其降低到这一层
     *
     * @param type 收费类型
     */
    public CashContext(String type) {
    
    
        switch (type) {
    
    
            case "正常收费":
                cashSuper = new CashNormal();
                break;
            case "满300返100":
                cashSuper = new CashReturn(300, 100);
                break;
            case "打8折":
                cashSuper = new CashRebate(0.8);
                break;
        }
    }

    /**
     * 获取结果
     *
     * @param money
     * @return
     */
    public double GetResult(double money) {
    
    
        double result = cashSuper.acceptCash(money);
        return result;
    }
}

收费客户端

package com.fafa.designmode.strategy;

/**
 * 收费客户端
 *
 * @author Sire
 * @version 1.0
 * @date 2022-03-05 18:21
 */
public class CashClient {
    
    
    public static void main(String[] args) {
    
    
        double money = 1900D;
        //        String type = "正常收费";
        //        String type = "打8折";
        String type = "满300返100";
        CashContext cashContext = new CashContext(type);
        double result = cashContext.GetResult(money);
        System.out.println("应收:" + result);
    }
}

三、策略模式和简单工厂模式的异同?

主要参考的这篇博客 策略模式和简单工厂模式的异同

从上面的例子程序来看,好像这个策略模式和简单工厂模式很相似啊

其实还是有差别的,不然怎么会分成两个模式呢?

  • 区别:
    1. 从类型上说:简单工厂模式属于创建型模式,而策略模式属于行为型模式。
    2. 简单工厂模式:根据客户选择的条件,来帮客户创建一个对象。
      策略模式:客户给它一个创建好的对象,它来帮客户做相应的事。

总结

首先来看一下两种模式的客户端代码:

//简单工厂模式的客户端:
Operation op;
//交给简单工厂类创建对象
op = OperationFactory.CreateOperate("+");
op.StrNumberA = 10;
op.StrNumberB = 20;
//调用生成对象的方法
double result = op.GetResult();
Console.WriteLine(result);
//策略模式的客户端:
double total = 0;
private void btnOk_Click(object sender, EventArgs e)
{
    
    
    CashContext cc = null;
    //客户端自己创建对象
    switch(cbxType.SelectedItem.ToString())
    {
    
    
        case: "正常收费":
            cc = new CashContext(new CashNormal());
            break;
        case: "满300返100":
            cc = new CashContext(new CashReturn());
            break;  
        case: "打8折":
            cc = new CashContext(new CashRebate());
            break;  
    }
    //计算具体策略收取的费用,交给context类执行相应的方法,客户端只需要接收返回的值就可以
    double acceptMoney = cc.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text));
    //计算总费用
    total += acceptMoney;
    listBox1.Items.Add("单价:" + txtPrice.Text + " 数量:" + txtNum.Text + " " + comboBox1.SelectedItem.ToString() + "总计:" + acceptMoney);
    lblResult.Text = total.ToString();
}

通过比较客户端的代码发现:

简单工厂模式:将对象的选择创建交给了简单工厂类,客户端只需要输入相应的条件就可以,不用负责对象的创建,但是需要客户端自己调用算法类的方法。

但是一旦需要增加新的运算类,比如开根运算,就要去修改简单工厂类。

策略模式:对象的选择创建仍需要自己来做,但是将调用方法的职责交给了Context类。一旦需要增加新的策略需要修改客户端。

因此,简单工厂模式的缺点就是当有新的需求增加时,需要频繁的修改工厂类。只用策略模式,当有新的需求增加时需要修改的是客户端,客户端仍然承担着

创建对象的职责,并没有减轻客户端的压力。而将这两种模式结合起来使用,则需要修改 Context 类,总之不是完美的。

猜你喜欢

转载自blog.csdn.net/a648119398/article/details/123302904