简述
设计模式类型有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设计模式,刘伟 编著