Java设计模式-策略模式

策略模式: 定义一系列的算法, 将其一个个封装起来, 并使它们可相互替换, 使得算法可独立于使用它的客户而变化.

(图片来源: 设计模式: 可复用面向对象软件的基础)

策略模式对应于解决某一问题的一个算法族, 允许用户从该算法族中任选一个算法解决该问题, 同时可以方便的更换算法或者增加新的算法. 并由客户端决定调用哪个算法(核心: 分离算法, 选择实现).

模式实现

案例: 商场打折 -策略可以简单分为: 原价购买、满减、返利三种策略:

Strategy

抽象策略: 定义算法族中所有算法的公共接口, Context使用这个接口来调用ConcreteStrategy定义的算法:

/**
 * @author jifang
 * @since 16/8/29 下午7:43.
 */
public interface Strategy {
    double acceptCash(double money);
}

ConcreteStrategy

具体策略: 以Strategy接口实现某具体算法或行为:

// 正常收费
class Normal implements Strategy {
    @Override
    public double acceptCash(double money) {
        return money;
    }
}
// 打折收费
class Discount implements Strategy {
    private double rate;
    public Discount(double rate) {
        if (rate > 1.0) {
            throw new RuntimeException("折扣力度怎么能大于1.0?");
        }
        this.rate = rate;
    }
    @Override
    public double acceptCash(double money) {
        return money * rate;
    }
}
// 返利收费
class Rebate implements Strategy {
    private double cashState;
    private double cashReturn;
    public Rebate(double cashState, double cashReturn) {
        this.cashState = cashState;
        this.cashReturn = cashReturn;
    }
    @Override
    public double acceptCash(double money) {
        if (money > cashState) {
            money -= Math.floor(money / cashState) * cashReturn;
        }
        return money;
    }
}

Context

上下文:

维护一个Strategy对象的引用;

定义一个接口让Strategy访问它的数据;

public class Context {
    private Strategy strategy;
    public void setStrategy(Type type, double... args) {
        if (type == Type.NORMAL) {
            strategy = new Normal();
        } else if (type == Type.DISCOUNT) {
            strategy = new Discount(args[0]);
        } else if (type == Type.REBATE) {
            strategy = new Rebate(args[0], args[1]);
        }
    }
    public double getResult(double money) {
        return strategy.acceptCash(money);
    }
    public enum Type {
        NORMAL(0, "正常"),
        DISCOUNT(1, "打折"),
        REBATE(2, "返利");
        private int value;
        private String desc;
        Type(int value, String desc) {
            this.value = value;
            this.desc = desc;
        }
    }
}

注: 将客户端需要选择具体Strategy的任务交给Context完成:

在基础策略模式中,选择所用具体Strategy实现的职责由Client承担, 并将其传递给Context, 这种方案对Client的负担较重, 因此将Context与简单工厂融合, 选择算法实现的工作改由Context负责.

Client

仅与Context交互: 通常有一系列的ConcreteStrategy可供选择.

public class Client {
    @Test
    public void client() {
        double money = 1000;
        Context context = new Context();
        context.setStrategy(Context.Type.NORMAL);
        System.out.println("原价: [" + context.getResult(money) + "]");
        context.setStrategy(Context.Type.REBATE, 100, 20);
        System.out.println("满100返20: [" + context.getResult(money) + "]");
        context.setStrategy(Context.Type.DISCOUNT, 0.8);
        System.out.println("6折优惠: [" + context.getResult(money) + "]");
    }
}

小结

作用

析取算法: Strategy接口为Context定义了一个可重用的算法/行为, 继承/实现其有助于析取出算法族的公共功能, 且可减少算法与Client间的耦合.

消除条件语句: 避免将不同行为堆砌在一个类中, 将行为封装在独立的Strategy实现中, 可在Client中消除条件语句.

简化单元测试: 每个算法都有自己的类, 可以单独测试.

场景

当使用一个算法的不同变体, 且这些变体可以实现为一个算法族时;

算法的客户不需要知晓其内部数据, 策略模式可以避免暴露复杂的、与算法相关的数据结构;

一个类定义了多种行为, 且这些行为以多个条件语句形式出现, 可将相关行为各自的Strategy(如: Servlet-api service()方法).

相关模式

Flyweight: Strategy对象经常是很好的轻量级对象.

原文发布于微信公众号 - Java帮帮(javahelp)

原文发表时间:2017-01-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据和云

未完待续:关于DB Link和SCN,你还需要知道的是...

前情回顾: 更新通报:Oracle修正了关于DB Link补丁的公告 解决方案:Oracle的DB Link问题及升级路线详述 预警揭秘:11.2.0.4前版必...

3637
来自专栏向治洪

android软件开发之webView.addJavascriptInterface循环渐进【一】

首先必要的啰嗦几句,这几天写VC写的累的要死,突然间不想再写想VC了,手里面有一个andriod的手机天天玩到半夜,却从来没有写过这方面的程序,真的是悲哀啊。所...

4037
来自专栏何俊林

FFmpeg实现多段小视频合成

4422
来自专栏吉浦迅科技

DAY39:阅读扩展数据类型

1472
来自专栏屈定‘s Blog

由需求而产生的一款db导出excel的工具

程序员最大的毛病可能就是懒,因为懒所以做出了许许多多提高自己工作效率的工具. 起因于我是商业开发,既然是商业项目避免不了各种数据统计,虽然公司有专门的数据平台,...

1675
来自专栏desperate633

设计模式之状态模式(state模式)状态模式的具体实例状态模式的分析

面向对象编程中,类用来表示对象,一般情况下,我们需要考虑用类来表示什么具体的东西。类对应的东西可能存在于真实世界中,也可能不存在于真实世界中。 状态模式所表示...

1012
来自专栏小红豆的数据分析

小蛇学python(12)分析《今生今世》人物关系图谱

《今生今世》是渣男胡兰成所写的一部自传体小说。今天我们就来分析一下在他所写的自传中的人物关系图谱,分析一下胡兰成到底和多少女人有关系。

5523
来自专栏向治洪

百度地图之标注聚会

俗话说站在巨人的肩膀上将事半功倍,在写android的百度地图标注物聚合时,我在网上也进行了大量的查询,发现标注物聚合的算法很早就有人写了,不过他们是js或者是...

2296
来自专栏向治洪

Kotlin和anko融合进行Android开发

kotlin是一门基于jvm的编程语言,最近进行了关于kotlin和 anko的研究。并且结合现在的APP设计模式,设想了初步的开发方式。并且准备应用在新的项目...

1976
来自专栏小詹同学

​我拿 12 年 36 套四级真题做了什么 ?

不会英语的程序员不是好程序员 ?小詹不敢乱立 flag ,但是我知道的是程序员就喜欢自己动手干些实事 ,比如今天教大家自己动手做个有意思的项目——从历年四级英语...

1591

扫码关注云+社区

领取腾讯云代金券