文章目录
前言
文章内容主要参考了刘伟主编的《设计模式(第2版)》,同时也结合了自己的一些思考和理解,希望能帮到大家。
本篇讲解策略模式。非常常见,也非常简单容易理解。
正文
一、定义
策略模式(Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化。
这个模式使得我们可以在根据环境或者条件的不同选择不同的策略来完成该任务。将解决途径进行封装有利于我们对解决方式的增加或删除。符合开闭原则。
二、情景假设
软件公司为某电影院开发了一套影院售票系统,在该系统中需要为不同类型的用户提供不同的电影票打折方式,具体打折方案如下:
(1) 学生凭学生证可享受票价8折优惠;
(2) 年龄在10周岁及以下的儿童可享受每张票减免10元的优惠;
(3) 影院VIP用户除享受票价半价优惠外还可进行积分。
三、情景分析
关于上面情景的类图(具体分析在下面)
抽象策略类Discount
public interface Discount{
public double calculate(double price);
}
三个具体策略类
//学生优惠
public class StudentDiscount implements Discount{
public double calculate(double price){
System.out.println("学生票:");
return price*0.8;
}
}
//儿童优惠
public class ChildDiscount implements Discount{
public double calculate(double price){
System.out.println("儿童票:");
return price-10;
}
}
//VIP优惠
public class VIPDiscount implements Discount
{
public double calculate(double price){
System.out.println("VIP票:");
System.out.println("增加积分!");
return price*0.5;
}
}
环境类买票MovieTicket
public class MovieTicket {
private double price;
private Discount discount;
public void setPrice(double price){
this.price = price;
}
public void setDiscount(Discount d){
this.discount = d;
}
public double getPrice(){
return discount.calculate(price);
}
}
客户端Client
public class Client {
public static void main(String[] args) {
MovieTicket mt;
Discount discount;
discount = (Discount)XMLUtil.getBean();//相当于获取特定的对象,如VIPDdiscount类
mt = new MovieTicket(discount);
mt.setPrice(100);
System.out.println("优惠后的价格:"+mt.getPrice());
}
}
工具类XMLUtil帮助我们读取XML文件并返回我们想要的内容给我们。
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
public class XMLUtil
{
//该方法用于从XML配置文件中提取对应对象,并返回对象
public static String getBean()
{
try
{
//创建文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("config.xml"));
//获取包含类名的文本节点
NodeList nl = doc.getElementsByTagName("name");
Node classNode = nl.item(0).getFirstChild();
String name = classNode.getNodeValue().trim();
return name;
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
}
接着就是我们的配置文件config.xml
<?xml version="1.0"?>
<config>
<name>VIPDiscount</name>
</config>
我们通过将买票的优惠方式进行封装,对应于一个类,那么这里就可以免去了过多的ifelse语句,当然给每一个策略添加一个总的抽象类是必须的。之后环境类根据抽象类编程即可。这就是策略模式非常的简单。
四、 模式分析
模式类图:
- Context: 环境类
- Strategy: 抽象策略类
- ConcreteSrategy: 具体策略类
(1) 模式特点
- 策略模式提供了对“开闭原则”的完美支持。
- 策略模式提供了管理相关的算法族的办法。
- 使用策略模式可以避免使用多重条件转移语句。
(2) 模式缺点
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类
- 策略模式将造成产生很多策略类和对象,可以通过享元模式在一定程度上减少对象的数量。
五、使用情景
- 如果在一个系统里面有许多类,他们之间的区别仅在于他们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种,那么可以将这些算法封装到一个个的具体算法类里面,而这些具体算法类都是一个抽象算法类的子类。
- 如果一个对象有很多行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句实现。
- 不希望客户知道复杂度、与算法相关的数据结构,在具体策略类中封装算法和相关的数据结构,提高算法的保密性与安全性。
六、拓展与延申
- 策略模式与状态模式是非常相近的
- 如果环境角色存在多种状态而且需要互相转化就应当使用状态模式。
- 策略模式中策略的选择是客户自己选择的,无关环境,而状态模式与环境情况非常密切,会因为外界因素而改变状态。
总结
本篇文章主要介绍设计模式的策略模式,非常简单,但是不要和状态模式弄混淆了!