架构师之路之设计模式一:策略模式

小弟最近在研究设计模式,准备边学边发博客,与众多大佬们交流学习,希望各位能够指出不足之处(废话不多说了,直接开花)

        首先,最起码得知道为啥学习设计模式;不要被那些设计模式学了也用不上所误导,虽然设计模式的研究不是那么简单,现在所流行的设计模式也远不止23种,但是多学习设计模式,你会被那些编程大师们的编程思想所洗礼,要知道,编程并不是一个工作,而是一门哲学,面向对象编程体会颇深。在日常开发中,或许用或者不用设计模式,都能实现你的业务需求,但是,用设计模式会使你的代码日后更易于维护,(你说你代码写一次以后就不改了?牛逼,出门右拐,谢谢),往往用适当的设计模式,会使你在日后维护、升级代码上更加得心应手,能够很大几率避免牵一发而动全身的几率,(有过体会的很难受有木有,吼吼吼,改一个小功能,狠不得把整个工程重构),所以能够在日常开发中,学会常用一些符合你业务需求的设计模式,不往你是一个苦逼的程序猿,哈哈! 

今天要说的设计模式使策略设计模式(Strategy)它定义了算法家族,分别封装起来,让算法与算法之间可以享胡替换,此模式的算法变化,不会影响到使用此算法的客户。 


策略模式适用于什么场景呢?

主要解决的是你的系统里有很多相似的算法,你用if...else去维护很麻烦很复杂,比如说,商场逢年过节会推出打折活动;

此时让你去设计一个商场的商品购买后台,你需要实现  打八折 打五折  打一折  免费送(做梦) 满500返200........等等等各种算法,此时你就不得不去做各种判断,废话不多说,怼代码! 

0.先看下策略模式的结构图 

 

结构图
设计图:策略模式

1.先写个商品类备用

package com.huangfu;

/**
 * 商品类
 * @author 皇甫
 */
public class Product {
    private String name;
    private double price;

    @Override
    public String toString() {
        return "Product{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public Product() {
    }

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }
}

2. 定义收费接口

package com.huangfu;

/**
 * 商场的收费接口类,应对商场的各种打折方式
 * @author 皇甫
 */
public interface Toll {
    /**
     * 商场的优惠方式
     * @param money   原价
     * @return        应付价格
     */
    public double offerMethod(double money);
}

3.书写算法的实现类 实现商场的各种打折方式 

package com.huangfu;

/**
 * 商场正常收费  没有优惠
 * @author 皇甫
 */
public class NoDiscount implements Toll{
    /**
     *
     * @param money   原价
     * @return 返回商品原价
     */
    @Override
    public double offerMethod(double money) {
        return money;
    }
}
package com.huangfu;

/**
 * 商场的额返利算法  入满300返100
 * @author 皇甫
 *
 */
public class RebateAlgorithm implements Toll {
    /**
     * 商场的返利力度
     */
    private double strength;
    private double scale;

    /**
     * @param strength  商场的返利力度  比如返100
     * @param scale     商场的返利满足条件  比如满足300
     */
    public RebateAlgorithm(double strength, double scale) {
        this.strength = strength;
        this.scale = scale;
    }

    /**
     * @param money   原价
     * @return 优惠后的价格
     */
    @Override
    public double offerMethod(double money) {
        double result = 0.0;
        if(money>=scale){
            result = (strength/scale) * money;
        }
        return money - result;
    }
}

 

package com.huangfu;

/**
 * 打折
 * 商场打折的折扣算法
 * @author 皇甫
 */
public class DiscountAlgorithm implements Toll{
    /**
     * 商场的折扣力度入打8折就是0.8
     * */
    private double strength;

    public DiscountAlgorithm(double strength) {
        this.strength = strength;
    }

    @Override
    public double offerMethod(double money) {
        return money*strength;
    }


}

 4.定义策略模式主体,管理各种算法

 

package com.huangfu;

/**
 * 策略模式算法主体类
 * @author 皇甫
 */
public class Content {
    /**
     * 将算法关联到此主题类  我的理解是将各种算法交由主题类来管理
     * */
    private Toll t;

    /**
     * 指定算法实现
     * @param t
     */
    public Content(Toll t) {
        this.t = t;
    }

    /**
     * 返回优惠力度
     * @param money
     * @return
     */
    public double getResult(double money){
        return t.offerMethod(money);
    }
}

5.使用简单工厂管理策略主体类(你也可以不用,没人逼你;工厂模式后面会发表,持续关注喽!)

package com.huangfu;

/**
 * 商品计算的简单工厂
 * @author 皇甫
 */
public class CommodityFactory {
    /**
     * 默认正常收费 没有任何优惠力度
     */
    private static Content c = new Content(new NoDiscount());

    /**
     * 设置优惠方式
     * @param type 优惠方式
     */
    public static void setOffer(String type){
        switch (type){
            case "打八折":
                c = new Content(new DiscountAlgorithm(0.8));
            case "满300返100":
                c = new Content(new RebateAlgorithm(100, 300));
        }
    }

    /**
     * 返回最终的优惠价格
     * @param money 应付价格
     * @return 实付价格
     */
    public static double getResult(double money){
        return c.getResult(money);
    }
}

 6.大功告成,测试走起,模拟购买商品

package com.huangfu;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

/**
 * 测试类
 * @author 皇甫
 */
public class TestMain {
    private static double price = 0.0;
    private static String type = "暂无优惠";
    /**
     * 模拟购买
     * @param args
     */
    public static void main(String[] args) {
        type = "满300返100";
        /**
         * 商场设置优惠方式  默认没有优惠
         */
        //CommodityFactory.setOffer(type);
        CommodityFactory.setOffer(type);

        Product p1 =  new Product("超大冰淇淋", 100.0);
        Product p2 =  new Product("风扇", 89.0);
        Product p3 =  new Product("口香糖", 32.5);
        Product p4 =  new Product("卫龙", 55.2);
        Product p5 =  new Product("大面筋", 215.0);
        Product p6 =  new Product("超大鱿鱼", 1000.5);
        Product p7 =  new Product("八爪鱼酱", 55.5);
        Product p8 =  new Product("小熊饼干", 66.6);
        Map<Integer,Product> product = new HashMap<Integer,Product>();
        product.put(1, p1);
        product.put(2, p2);
        product.put(3, p3);
        product.put(4, p4);
        product.put(5, p5);
        product.put(6, p6);
        product.put(7, p7);
        product.put(8, p8);

        while (true){
            Set<Map.Entry<Integer, Product>> entries = product.entrySet();
            for (Map.Entry<Integer, Product> entry : entries) {
                System.out.println(entry.getKey()+":"+entry.getValue().getName()+" 价格"+entry.getValue().getPrice());
            }

            System.out.println("-------------------请输入您要购买的商品序号(现在的优惠为"+type+")-现在总计为:"+price+"元,输入0结算--------------------");
            Scanner scanner = new Scanner(System.in);
            int i = scanner.nextInt();
            if(i==0){
                break;
            }
            price+=product.get(i).getPrice();
            System.out.println("购买成功 输入0结束购买");
        }
        //最终价格
        double result = CommodityFactory.getResult(price);
        System.out.println("实际付款"+result+"元");
    }
}

 7.查看结果

 

D:\java\jdk\bin\java.exe "-javaagent:D:\idea\IntelliJ IDEA 2018.2.1\lib\idea_rt.jar=4289:D:\idea\IntelliJ IDEA 2018.2.1\bin" -Dfile.encoding=UTF-8 -classpath D:\java\jdk\jre\lib\charsets.jar;D:\java\jdk\jre\lib\deploy.jar;D:\java\jdk\jre\lib\ext\access-bridge-64.jar;D:\java\jdk\jre\lib\ext\cldrdata.jar;D:\java\jdk\jre\lib\ext\dnsns.jar;D:\java\jdk\jre\lib\ext\jaccess.jar;D:\java\jdk\jre\lib\ext\jfxrt.jar;D:\java\jdk\jre\lib\ext\localedata.jar;D:\java\jdk\jre\lib\ext\nashorn.jar;D:\java\jdk\jre\lib\ext\sunec.jar;D:\java\jdk\jre\lib\ext\sunjce_provider.jar;D:\java\jdk\jre\lib\ext\sunmscapi.jar;D:\java\jdk\jre\lib\ext\sunpkcs11.jar;D:\java\jdk\jre\lib\ext\zipfs.jar;D:\java\jdk\jre\lib\javaws.jar;D:\java\jdk\jre\lib\jce.jar;D:\java\jdk\jre\lib\jfr.jar;D:\java\jdk\jre\lib\jfxswt.jar;D:\java\jdk\jre\lib\jsse.jar;D:\java\jdk\jre\lib\management-agent.jar;D:\java\jdk\jre\lib\plugin.jar;D:\java\jdk\jre\lib\resources.jar;D:\java\jdk\jre\lib\rt.jar;D:\ideaWorkSpace\20190109\springboot_ueditor\target\classes com.huangfu.TestMain
1:超大冰淇淋 价格100.0
2:风扇 价格89.0
3:口香糖 价格32.5
4:卫龙 价格55.2
5:大面筋 价格215.0
6:超大鱿鱼 价格1000.5
7:八爪鱼酱 价格55.5
8:小熊饼干 价格66.6
-------------------请输入您要购买的商品序号(现在的优惠为满300返100)-现在总计为:0.0元,输入0结算--------------------
1
购买成功 输入0结束购买
1:超大冰淇淋 价格100.0
2:风扇 价格89.0
3:口香糖 价格32.5
4:卫龙 价格55.2
5:大面筋 价格215.0
6:超大鱿鱼 价格1000.5
7:八爪鱼酱 价格55.5
8:小熊饼干 价格66.6
-------------------请输入您要购买的商品序号(现在的优惠为满300返100)-现在总计为:100.0元,输入0结算--------------------
1
购买成功 输入0结束购买
1:超大冰淇淋 价格100.0
2:风扇 价格89.0
3:口香糖 价格32.5
4:卫龙 价格55.2
5:大面筋 价格215.0
6:超大鱿鱼 价格1000.5
7:八爪鱼酱 价格55.5
8:小熊饼干 价格66.6
-------------------请输入您要购买的商品序号(现在的优惠为满300返100)-现在总计为:200.0元,输入0结算--------------------
1
购买成功 输入0结束购买
1:超大冰淇淋 价格100.0
2:风扇 价格89.0
3:口香糖 价格32.5
4:卫龙 价格55.2
5:大面筋 价格215.0
6:超大鱿鱼 价格1000.5
7:八爪鱼酱 价格55.5
8:小熊饼干 价格66.6
-------------------请输入您要购买的商品序号(现在的优惠为满300返100)-现在总计为:300.0元,输入0结算--------------------
0
实际付款200.0元

Process finished with exit code 0

8.总结

       策略模式中封装了变化,在官方定义上,策略模式就是用来封装算法的,可是在实际的业务场景中,策略模式几乎可以封装任何类型的规则。在业务分析中,只要应用到"在不同的时间应用不同的规则"这句话几乎都可以使用到策略模式,就比如上面那个例子,日后商场再增加任何算法,只需要再新增算法种类并继承优惠接口就可以了,当然需要更改工厂方法里面的switch语句(任何方法的改动都需要付出代价,后面会提到改进方法,提示:反射)就可以了,每一种算法都封装到一个类中,满足功能单一性,而且每个类负责一个算法不宜出错;所有算法继承同一个接口,方便日后的扩展,何乐而不为呢?本次就到这了,下期见!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值