1.什么是策略模式
定义一系列算法,将每个算法封装起来,并让他们可以相互替换。策略模式让算法可以独立于使用它的客户而变化。
举个栗子:做查询可能有多种方法,如果用if else来进行选择,是硬编码,肯定不行
策略模式又叫政策模式。
2.策略模式的结构
(1)Context(环境类):环境类是使用算法的角色,它在解决某个问题时采用多种策略。在环境类中维持了一个对抽象策略类的引用实例,用于定义所采用的策略。
(2)Strategy(抽象策略类):抽象策略类为所支持的算法声明了抽象方法,是所有策略类的父类,它可以是抽象类或具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。
(3)ConcreteStrategy(具体策略类):具体策略类实现了在抽象策略类中声明的算法,在运行时具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务功能
3.策略模式的实现
(1)抽象策略类
/**
* 抽象策略类
*/
public abstract class AbstractStrategy {
public abstract void algorithm();//声明抽象算法
}
(2)具体策略类
/**
* 具体策略类
*/
public class ConcreteStrategyA extends AbstractStrategy {
@Override
public void algorithm() {
//算法A
}
}
(3)环境类
/**
* 环境类
*/
public class Context {
private AbstractStrategy strategy;//维持一个对抽象策略类的引用
public void setStrategy(AbstractStrategy strategy){
this.strategy = strategy;
}
//调用策略类中的算法
public void algorithm(){
strategy.algorithm();
}
}
(4)客户端
public class Client {
public static void main(String[] args) {
//...
Context context = new Context();
AbstractStrategy strategy;
strategy = new ConcreteStrategyA();//可在运行时指定类型,通过配置文件和反射机制实现
context.setStrategy(strategy);
context.algorithm();
//...
}
}
4.策略模式实例——电影票为不同人群提供不同折扣
(1)电影票类,充当环境类
/**
* 电影票类,充当环境类
*/
public class MovieTicket {
private double price;
private Discount discount;//维持一个对抽象折扣类的引用
//注入一个折扣类对象
public void setDiscount(Discount discount) {
this.discount = discount;
}
public void setPrice(double price) {
this.price = price;
}
public double getPrice(){
//调用折扣类的折扣价计算方法
return discount.calculate(this.price);
}
}
(2)折扣类,充当抽象策略类
/**
* 折扣类,充当抽象策略类
*/
public interface Discount {
public double calculate(double price);
}
(3)学生票折扣类,充当具体策略类
/**
* 学生票折扣类,充当具体策略类
*/
public class StudentDiscount implements Discount {
private final double DISCOUNT = 0.8;
@Override
public double calculate(double price) {
System.out.println("学生票:");
return price * DISCOUNT;
}
}
(4)儿童票折扣类,充当具体策略类
/**
* 儿童票折扣类,充当具体策略类
*/
public class ChildrenDiscount implements Discount {
private final double DISCOUNT = 10;
@Override
public double calculate(double price) {
System.out.println("儿童票");
if(price >= 20){
return price - DISCOUNT;
}else {
return price;
}
}
}
(5)VIP会员票折扣类,充当具体策略者
/**
* VIP会员票折扣类,充当具体策略者
*/
public class VIPDiscount implements Discount {
private final double DISCOUNT = 0.5;
@Override
public double calculate(double price) {
System.out.println("VIP票");
System.out.println("增加积分");
return price * 0.5;
}
}
(6)配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<config>
<className>controller.strategyModuleMovie.StudentDiscount</className>
</config>
(7)工具类
public class XMLUtil {
/**
* 从xml配置文件中提取具体类的类名,并返回一个实例对象
*/
public static Object getBean(){
try {
//创建DOM文档对象
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
Document document = builder.parse(new File("src//controller//strategyModuleMovie//config.xml"));
//获取包含类名的文本节点
NodeList nl = document.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;
}
}
}
(8)客户端
public class Client {
public static void main(String[] args) {
MovieTicket mt = new MovieTicket();
double originalPrice = 60.0;
double currentPrice;
mt.setPrice(originalPrice);
System.out.println("原始价为:" + originalPrice);
System.out.println("------------------");
Discount discount;
discount = (Discount)XMLUtil.getBean();
mt.setDiscount(discount);
currentPrice = mt.getPrice();
System.out.println("折后价:"+currentPrice);
}
}
(9)路径及结果
5.javaSE中的布局管理
Container类充当环境角色,LayoutManager作为所有布局类的公共父类扮演抽象策略角色,具体子类则有BorderLayout,FlowLayout,GridLayout,GridBagLayout,CardLayout
6.策略模式优缺点
优:
(1)开闭原则
(2)避免重复代码
(3)可以替换继承关系
(4)可以避开多重条件选择语句
(5)复用
缺:
(1)客户端必须知道所有的策略
(2)策略类会过多
(3)无法同事在客户端使用多个策略类
7.使用环境
(1)系统动态在几种算法中选择一种
(2)一个对象有很多行为
(3)不希望客户知道复杂的数据结构