大话设计模式学习笔记(2)----策略模式

上篇我们学习了简单工厂模式,想必大家如果按照我写的步骤一步一步下来的话肯定会有印象(尤其是像我一样刚刚接触设计模式的小白白们)。这次我们继续学习策略模式,例子还是用作者给的吧~

问题提出:

需要设计一个商场的收银软件,营业员根据用户购买商品的单价和数量来计算总额。(考虑商场有多个促销活动(打折活动,满减活动)等,且由于我们是用java写的,写图形化界面不方便,所以把main方法看作是客户端)

大家看到这个想必第一个想到的就是我们学过的简单工厂模式(我也是)那么大家试着用简单工厂模式实现以下上述需求,顺便复习以下简单工厂咯~

以下是我写的简单工厂模式:

import java.util.Scanner;
public class Main {
    public static void main(String args[]) {
        Scanner scan = new Scanner(System.in);
        int kinds;
        Activity activity;
        while(scan.hasNext())
        {
            kinds = scan.nextInt();
            activity = ActivityFactory.getActivity(kinds);//根据输入的参数来决定使用哪种促销方式
        }
        System.out.println(activity2.money(50, 2));
    }
}

interface Activity {//定义活动的接口
    double money(double price, int amount);//输入单价和数量返回需要交多少钱
}

class A implements Activity// 活动A,打折活动
{
    private double rate;
    public A(double rate)
    {
        this.rate = rate;
    }
    public double money(double price, int amount) {
        return price * amount * rate;
    }
}

class B implements Activity// 活动B,满减活动
{
    private double moneyLimit;//达到多少满减
    private double moneyReturn;//满减多少
    public B(double moneyLimit,double monetReturn)
    {
        this.moneyLimit = moneyLimit;
        this.moneyReturn = monetReturn;
    }
    public double money(double price, int amount) {
        double cost = price * amount;
        if (cost >= moneyLimit) {
            cost -= moneyReturn;
        }
        return cost;
    }
}

class C implements Activity// 无活动,正常收费
{
    public double money(double price, int amount) {
        return price * amount;
    }
}

class ActivityFactory// 商家促销活动的工厂
{
    public static Activity getActivity(int kinds) {//根据输入活动的类型号来生成活动
        switch (kinds) {
        case 1://八折
            return new A(0.8);
        case 2://满100-50
            return new B(100,50);
        default://无活动
            return new C();
        }
    }
}

把简单工厂写出来以后大家想必美滋滋了吧~。但是简单工厂的侧重点是生产对象(工厂嘛~),但是其实客户端得到对象并没有什么用,客户端只需要得到最后的结果就可以了。所以我们需要把算法封装好,减少客户端的工作量。省去activity.money()这一步。
下面来看策略模式的实现:

import java.util.Scanner;
public class Main {
    public static void main(String args[]) {
        Scanner scan = new Scanner(System.in);
        int kinds;
        Context context;
        double money;
        while(scan.hasNext())
        {
            kinds = scan.nextInt();
            switch (kinds) {
            case 1:
                context = new Context(new A(0.8),50,2);
                money = context.getMoney();
                break;
            case 2:
                context = new Context(new B(100,50),50,2);
                money = context.getMoney();
                break;
            default:
                context = new Context(new C(),50,2);
                money = context.getMoney();
                break;
            }
            System.out.println(money);
        }
    }
}

interface Activity {// 定义活动的接口
    double money(double price, int amount);// 输入单价和数量返回需要交多少钱
}

class A implements Activity// 活动A,打折活动
{
    private double rate;

    public A(double rate) {
        this.rate = rate;
    }

    public double money(double price, int amount) {
        return price * amount * rate;
    }
}

class B implements Activity// 活动B,满减活动
{
    private double moneyLimit;// 达到多少满减
    private double moneyReturn;// 满减多少

    public B(double moneyLimit, double monetReturn) {
        this.moneyLimit = moneyLimit;
        this.moneyReturn = monetReturn;
    }

    public double money(double price, int amount) {
        double cost = price * amount;
        if (cost >= moneyLimit) {
            cost -= moneyReturn;
        }
        return cost;
    }
}

class C implements Activity// 无活动,正常收费
{
    public double money(double price, int amount) {
        return price * amount;
    }
}

class Context {
    Activity activity;
    double price;
    int amount;

    public Context(Activity activity,double price,int amount) {
        this.activity = activity;
        this.price = price;
        this.amount = amount;
    }

    public double getMoney() {
        return activity.money(price, amount);
    }
}

大家看代码应该能看到多了一个Context()类,里面存放了一个Activity类的对象activity。构造方法传入一个Activity参数并且初始化activity。然后再提供一个对外获取activity的接口。
大家可能看完策略模式以后会感觉跟简单工厂模式差不太多,但是细看就会发现客户端是得不到我们的算法对象的,也就是我们完成了算法的封装。让不同的算法之间可以相互替换。
UML图代码为:

 * @startuml
 * interface Activity{
 * + money():double
 * }
 * Activity<|..A
 * class A{
 * - rate:double
 * + A(double)
 * + money():double
 * }
 * Activity<|..B
 *  class B{
 * - moneyLimit:double
 * - moneyReturn:double
 * + B(double,double)
 * + money():double
 * }
 * Activity<|..C
 * class C{
 * + money():double
 * }
 * Context-->Activity
 * class Context{
 * -activity:Activity
 * -price:double
 * -amount:int
 * +Context(Activity,double,int)
 * +getMoney():double
 * }
 * @enduml

UML图为:
这里写图片描述
注:书中认为Context与Activity关系为聚合关系,但我感觉应该是关联关系。因为在Context里面只是保存了Activity的一个引用而已。

策略模式(Strategy):它定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户端。

但还有一个问题,我们在策略模式里面又把switch这么一大块的代码搬进了客户端里面(main方法)。这可不是什么好习惯,所以我们应该再进一步把这坨东西从客户端搬出来。

策略模式与简单工厂的结合

public class Main {
    public static void main(String args[]) {
        Scanner scan = new Scanner(System.in);
        int kinds;
        Context context;
        double money;
        while(scan.hasNext())
        {
            kinds = scan.nextInt();
            context = new Context(kinds, 50, 2);
            money = context.getMoney();
            System.out.println(money);
        }
    }
}
class Context {
    Activity activity;
    double price;
    int amount;

    public Context(int kinds,double price,int amount) {
        switch (kinds) {
        case 1:
            activity = new A(0.8);
            break;
        case 2:
            activity = new B(100, 50);
            break;
        default:
            activity = new C();
            break;
        }
        this.price = price;
        this.amount = amount;
    }

    public double getMoney() {
        return activity.money(price, amount);
    }
}

需要改的就只有客户端代码和Context代码。大家应该都能看懂吧,就是从客户端传入一个参数然后在Context里面进行判断。

最后摘抄一段书中的策略模式的好处:策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少各种算法类与使用算法类之间的耦合。简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值