Java设计模式 - 策略模式

策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。 --摘选自《JAVA与模式》

理论有些抽象,举个简单的例子各位就容易理解了...

我们去上课、上班、出差、旅游,需要选择合适的出行方式,是选择步行?公交?火车?还是飞机?...


哈哈,这种选择其实就是一种“策略”。当然,针对这个例子,一种出行方式可能满足不了我们的需求,我们可能需要搭配不同的出行方式出行,这种多重选择其实也是一种“策略”。

Java策略模式实战

今天小编准备根据现实实例,用Java写一个基于“策略模式”的解决方案。好了,小伙伴们赶快上车...

需求是这样的:某商场想要开展3种销售模式,而且可以相互之间任意选择转换...

第1种销售模式:正常销售

第2种销售模式:打折销售(如:全场商品9折、全场8折...)

第3种销售模式:返现销售(如:全场商品满500元返现100元)

直白点分析,其实就是让我们对用户购买商品的总金额进行“模式处理”,得到最终付款金额。

话不多说,开始上代码...

1.搭建抽象策略角色

/**
 * 价格策略接口(所有价格策略的父类)
 * Created by Wangnan on 2016/8/19.
 */
public interface PriceStrategyInterface {

    /**
     * 获取执行策略后得到的金额
     */
    float getStrategyResult();
}

2.构建具体策略角色(正常价格策略,打折价格策略,返现价格策略)

/**
 * @ClassName: NormalPriceStrategy
 * @Description: 正常价格策略
 * @Author Wangnan
 * @Date 2016/8/19
 */
public class NormalPriceStrategy implements PriceStrategyInterface{

    private float mPrice; // 用户购物总价
    
    public NormalPriceStrategy(float totalPrice){
        mPrice = totalPrice;
    }

    @Override
    public float getStrategyResult() {
        return mPrice;
    }
}

/**
 * @ClassName: DiscountPriceStrategy
 * @Description: 打折价格策略
 * @Author Wangnan
 * @Date 2016/8/19
 */
public class DiscountPriceStrategy implements PriceStrategyInterface{

    private float mPrice; // 用户购物总价
    private float mDiscountRate; // 折扣率(0F ~ 1F)

    public DiscountPriceStrategy(float price , float discount){
        mPrice = price;

        if(discount >= 0F && discount <= 1F) { //折扣率越界判断
            mDiscountRate = discount;
        }else{
            mDiscountRate = 1;
        }
    }

    @Override
    public float getStrategyResult() {
        return mPrice * mDiscountRate;
    }
}

/**
 * @ClassName: ReturnPriceStrategy
 * @Description: 返现价格策略
 * @Author Wangnan
 * @Date 2016/8/19
 */
public class ReturnPriceStrategy implements PriceStrategyInterface{

    private float mPrice; // 用户购买总价
    private float mReturnPriceStandard; // 返现标准
    private float mReturnPrice; // (满足返现标准) 返现金额

    public ReturnPriceStrategy(float price, float returnPriceStandard, float returnPrice){
        mPrice = price;
        mReturnPriceStandard = returnPriceStandard;
        mReturnPrice = returnPrice;
    }

    @Override
    public float getStrategyResult() {
        if(mPrice > mReturnPriceStandard){
            return mPrice - (( mPrice / mReturnPriceStandard) * mReturnPrice); // 返现叠加:(举例)满300减100,满600减200,...依次类推
        }else {
            return mPrice;
        }
    }
}

3.构造环境角色。【环境角色:持有一个策略类的引用,最终给客户端调用。其实就是策略的调度者(或者说是执行者)】

/**
 * @ClassName: PriceContext
 * @Description: 价格环境角色
 * @Author Wangnan
 * @Date 2016/8/19
 */
public class PriceContext {

    private PriceStrategyInterface mPriceStrategyInterface; // 价格策略接口

    public PriceContext(PriceStrategyInterface priceStrategyInterface){
        mPriceStrategyInterface = priceStrategyInterface;
    }

    /**
     * 执行价格策略 -> 调度策略对象,获取最终价格
     */
    public float executePriceStrategy(){
        return mPriceStrategyInterface.getStrategyResult();
    }
}

4.策略模式构造完毕,开始使用(这里给出了3种策略的使用方式)。

    // 假设用户购买1000元商品,商场没有购物活动
    float mPrice = 1000F;
    PriceContext context = new PriceContext(new NormalPriceStrategy(mPrice)); // 走正常价格策略
    float finalPrice = context.executePriceStrategy(); // 执行策略,finalPrice = 1000.0

    // 假设用户购买1000元商品,商场进行全场商品打9折活动
    float mPrice2 = 1000F;
    float discountRate = 0.9F;
    PriceContext context2 = new PriceContext(new DiscountPriceStrategy(mPrice2, discountRate)); // 走打折价格策略
    float finalPrice2 = context2.executePriceStrategy(); // 执行策略,finalPrice2 = 900.0

    // 假设用户购买1000元商品,商场进行全场商品满500减100返现活动
    float mPrice3 = 1000F;
    float returnPriceStandard = 500F; // 返现标准
    float returnPrice = 100F; // (满足返现标准)返现金额
    PriceContext context3 = new PriceContext(new ReturnPriceStrategy(mPrice3, returnPriceStandard, returnPrice)); // 走返现价格策略
    float finalPrice3 = context3.executePriceStrategy(); // 执行策略,finalPrice3 = 800.0

至此,我们的“策略模式”就结束了,看完的朋友是不是觉得有点小题大做,把简单的问题给复杂化了呢...哈哈,针对这个问题确实是!但是,如果你的需求更加多样,更加复杂...你会发现这种设计模式其实可以把你的复杂问题简单化、流程化...

总结

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化,使算法自身更具灵活性。

拓展

针对看过我上一篇文章Java设计模式 - 简单工厂模式的朋友,我给你们带来一个新的福利 - 组合两种设计模式,我们常常听说或正在使用的MVC、MVP、MVVM...等模式,其实在很大程度上是将设计模式进行组合规整后形成的...我们今天也要组合一个新模式 - 简单策略工厂模式(将调度的策略进一步用简单工厂模式进行封装,让工厂去生产我们需要的策略)。

1.开始改造价格环境角色,封装价格策略工厂

/**
 * @ClassName: PriceContext
 * @Description: 价格环境角色
 * @Author Wangnan
 * @Date 2016/8/19
 */
public class PriceContext {

    private PriceStrategyInterface mPriceStrategyInterface; // 价格策略接口

    public static final int TYPE_NORMAL_PRICE = 0x0001; // 正常价格策略标识符
    public static final int TYPE_DISCOUNT_PRICE = 0x0002; // 折扣价格策略标识符
    public static final int TYPE_RETURN_PRICE = 0x0003; // 返现价格策略标识符

    /**
     *
     * 创建环境角色
     * @param type TYPE_NORMAL_PRICE(正常价格策略),TYPE_DISCOUNT_PRICE(折扣价格策略) or TYPE_RETURN_PRICE(返现价格策略)
     * @param args type = TYPE_NORMAL_PRICE时,只需传入购物总价(args[0])。
     *             type = TYPE_DISCOUNT_PRICE时, 需要传入购物总价(args[0])和折扣率(args[1])
     *             type = TYPE_RETURN_PRICE时,需要传入购物总价(args[0])、返现价格标准(args[1])和返现价格(args[2])
     */
    public PriceContext(int type, float...args){
        switch (type){
            case TYPE_NORMAL_PRICE:
                mPriceStrategyInterface = new NormalPriceStrategy(args[0]); // 创建正常价格策略
                break;
            case TYPE_DISCOUNT_PRICE:
                mPriceStrategyInterface = new DiscountPriceStrategy(args[0], args[1]); // 创建折扣价格策略
                break;
            case TYPE_RETURN_PRICE:
                mPriceStrategyInterface = new ReturnPriceStrategy(args[0], args[1], args[2]); // 创建返现价格策略
                break;
            default:
                mPriceStrategyInterface = new NormalPriceStrategy(args[0]);
                break;
        }
    }

    /**
     * 调度策略对象,执行策略 -> 获取最终价格
     */
    public float executePriceStrategy(){
        return mPriceStrategyInterface.getStrategyResult();
    }
}

2.使用价格环境角色(举例)

    // 假设用户消费1000元,商品开展全场商品打8.8折活动
    PriceContext mPriceContext = new PriceContext(PriceContext.TYPE_DISCOUNT_PRICE, 1000, 0.88F);
    float finalPrice = mPriceContext.executePriceStrategy(); // finalPrice = 880.0

今天的内容就分享到这了...Good,Lucky!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容

  • 定义 策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可...
    步积阅读 762评论 0 2
  • 今天给大家说说田忌赛马的故事。如有雷同,纯属巧合!话说在战国时期,群雄割据,硝烟四起,茶余饭后还是少不了娱乐活动的...
    Jet啟思阅读 5,493评论 4 17
  • 一、定义 策略模式是指对一系列的算法定义,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使...
    怡红快绿阅读 865评论 0 0
  • 1.策略模式(Strategy Pattern) 分别封装行为接口,实现算法族,超类里放行为接口对象,在子类里具体...
    Mr_欢先生阅读 692评论 0 9
  • 今天周五很多人都进入了周末亲子活动模式,然而老刘家里静的只有墙上时钟的嘀嗒嘀嗒……时光一秒秒的流逝…小刘酒足饭饱后...
    豫行天下阅读 238评论 0 0