行为型之设计模式

简述

设计模式类型有3种(行为型,创建型,结构型),以下逐一列出行为型类型的设计模式:
模板方法,命令模式,访问者模式,迭代器模式,观察者模式,中介者,备忘录,解释器,状态,策略,职责连模式(责任链模式)

一、策略模式

封装多中计算方式的算法包。

一个简单的使用场景

需求场景:
电影院为不同类型用户提供不同电影票的打折方式,方案:
1 学生凭学生证享受8折优惠
2 年龄在1-周岁及以下儿童可享受每张电影票减免10元优惠(原始票价不能低于20)
3 vip 用户可享受5折优惠,与此同时额外获取积分,可用积分兑换影院赠品
后期可能还会有优惠折扣方案。

分析场景,抽离出关键点的简图

1 涉及到折扣方案的封装
2 针对不同角色的切换
3 后期要考虑的复用。
确认过眼神,正对策略模式。

4此场景的开发简图:
上图

实操demo

 public class Client {
    public static void main(String[] args) {
        //业务中通过一些前置条件,判断走孩子/vip/学生  折扣类
        BigDecimal originPrice=new BigDecimal("79.99");
        new MovieTicket(originPrice,new ChildrenDiscount()).getPrice();;

        originPrice=new BigDecimal("88");
         new MovieTicket(originPrice,new VIPDiscount()).getPrice();
 }
}
/**环境策略角色*/
public class MovieTicket {
    BigDecimal price;
    Discount discount;
    public MovieTicket(BigDecimal price,Discount discount) {
        this.price=price;
        this.discount=discount;
        System.out.println("原始票价为:"+price.toString());
    }
    public BigDecimal getPrice() {
        return discount.calculate(this.price);
    }

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

    public void setDiscount(Discount discount) {
       this.discount=discount;
    }
}
/**抽象策略角色*/
public interface Discount {
   BigDecimal calculate(BigDecimal originPrice);
}
/**具体策略角色*/
public class StudentDiscount implements Discount {
    private final BigDecimal DISCOUNT=new BigDecimal("0.8");
    @Override
    public BigDecimal calculate(BigDecimal originPrice) {
        BigDecimal price= originPrice.multiply(DISCOUNT).setScale(2,BigDecimal.ROUND_HALF_UP);
        System.out.println("学生票价:"+price.toString());
        return price;
    }
}
/**具体策略角色*/
public class ChildrenDiscount implements Discount{
    private final BigDecimal DISCOUNT=new BigDecimal(10);

    @Override
    public BigDecimal calculate(BigDecimal originPrice) {
        BigDecimal price=originPrice.compareTo(new BigDecimal(20))>=0?originPrice.subtract(DISCOUNT):originPrice;
        System.out.println("原票价至少20元,少儿票价方可优惠:"+price.toString());
        return price;
    }
}
/**具体策略角色*/
public class VIPDiscount implements  Discount {
    private final BigDecimal DISCOUNT=new BigDecimal("0.5");
    @Override
    public BigDecimal calculate(BigDecimal originPrice) {
        BigDecimal price= originPrice.multiply(DISCOUNT);
        System.out.println("VIP票价:"+price.toString()+"可积分");
        return price;
    }
}

以上为策略模式小demo,看到这就可以直接看小结了。
代码上传到csdn了,可以下载测试。

策略模式小结

工作中使用率蛮高的。
同类场景,eg1: 借贷平台的还款方式,可用策略模式去计算不同的还款方式:一次性还本付息,先息后本,等额本金,等额本息,弹性还款,这些算法包均可作为具体策略角色进行封装。
eg2:接存管平台接口开发时,比如预处理,调用接口 以及后处理,可以采取策略模式。

优点小结:
1 对某一业务数据操作行为有多个算法包,客户针对自己需求调用其中的一个算法。
2 可灵活切换,可复用,封装多个算法包,完美满足设计模式开闭原则,可扩展性强。

据说的劣势,客户端要知道每种算法的用户,然后对自己的需求去调用,但如果算法方案是从客户端需求发起呢,哈哈,工作中一般都是业务方发起需求,驱动科技落地,如果是这种,那么该缺点可以忽略。

以上小结仅供参考,并不全面,仅个人看中的层面的总结,如有差错,请不吝指教~

附注:

如果你还想要使用xml形式,可参看下面追加code。将具体策略模式配置到xml文件中,每次新加策略后,在xml文件中改一下重启一下服务即可,实现方式如下:

/** 1 Client2.class 将具体策略角色类配置到xml中,通过xml解析工具类获取该具体策略角色类的实例走后续流程*/
public class Client2 {
    public static void main(String[] args) {
        BigDecimal originalPrice=new BigDecimal(60.0);
        Discount disount=(Discount) XMLUtil.getBean();;//读取配置文件并反射生成具体折扣对象
        MovieTicket mt=new MovieTicket(originalPrice,disount);
        mt.getPrice();

    }
}
2 添加xml文件解析工具包

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;

public class XMLUtil {
    //该方法用于从xml配置文件中提取具体类的类名,并返回一个实例对象
    public static Object getBean(){
        try {
        DocumentBuilderFactory dFactory=DocumentBuilderFactory.newInstance();
        DocumentBuilder builder=dFactory.newDocumentBuilder();
        Document doc;
            doc=builder.parse(new File("src//strategyBook//config.xml"));

            //获取包含类型的文本节点
            NodeList nl=doc.getElementsByTagName("className");
            Node classNode=nl.item(0).getFirstChild();
            String cName=classNode.getNodeValue();

            //通过类名生成实例对象并将其返回
            Class c=Class.forName(cName);
            Object obj=c.newInstance();
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
3config.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<config>
        <className>strategyBook.VIPDiscount</className>
</config>

xml配置具体策略角色:
优点:每次新增可添加具体策略角色类,同步修改xml文件后重启即可。清晰明了
缺点,不够灵活,试想,面对的前置条件是不同角色,要走各自对应的具体策略角色,那岂不是每走完一次数据 都要修改配置文件,然后重启服务?

参阅:
[1]: java设计模式,刘伟 编著

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章