设计模式学习笔记(三)——策略模式
一、概述
策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们之间可以互相替换。策略模式使得算法可以在不影响客户端的情况下发生变化。
策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以互相替换。在策略模式中,调用算法的主体是封装到了封装类Context中,抽象策略Strategy一般是一个接口,目的只是为了定义规范,里面一般不包含逻辑。其实,这只是通用实现,而在实际编程中,因为各个具体策略实现类之间难免存在一些相同的逻辑,为了避免重复的代码,我们常常使用抽象类来担任Strategy的角色,在里面封装公共的代码。
二、实现策略模式
需求:
/** * 收费接口 * @author Administrator * */ public interface Charge { /** * 收费 * @param chargeFormDto * @return */ double charge(ChargeFormDto chargeFormDto); }
NormalCharge(正常收费):
/** * 具体 正常收费策略 * @author Administrator * */ public class NormalCharge implements Charge { @Override public double charge(ChargeFormDto chargeFormDto) { System.out.println("正常收费: " + chargeFormDto.getPrice()); return chargeFormDto.getPrice(); } }
DiscountCharge(打折收费):
/** * 具体 打折收费策略类 * @author Administrator * */ public class DiscountCharge implements Charge { @Override public double charge(ChargeFormDto chargeFormDto) { double price = chargeFormDto.getPrice() - chargeFormDto.getPrice() * chargeFormDto.getRebate(); System.out.println("打折收费: " + price); return price; } }
RebateCharge(返利收费):
/** * 具体 返利消费策略类 * @author Administrator * */ public class RebateCharge implements Charge { @Override public double charge(ChargeFormDto chargeFormDto) { double price = chargeFormDto.getPrice() - chargeFormDto.getPrice() / chargeFormDto.getFullCash() * chargeFormDto.getReturnCash(); System.out.println("返利消费, 消费:" + chargeFormDto.getPrice() + ", 返利: " + price); return price; } }
ChargeFormDto(收费传输对象):
/** * 收费表单传输对象 * @author Administrator * */ public class ChargeFormDto implements Serializable { /** * 打折类型 */ private String type; /** * 总价 */ private double price; /** * 折扣 */ private double rebate; /** * 满额度 */ private double fullCash; /** * 反额度 */ private double returnCash; public ChargeFormDto() { super(); } public ChargeFormDto(String type, double price, double rebate, double fullCash, double returnCash) { super(); this.type = type; this.price = price; this.rebate = rebate; this.fullCash = fullCash; this.returnCash = returnCash; } public String getType() { return type; } public void setType(String type) { this.type = type; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public double getRebate() { return rebate; } public void setRebate(double rebate) { this.rebate = rebate; } public double getFullCash() { return fullCash; } public void setFullCash(double fullCash) { this.fullCash = fullCash; } public double getReturnCash() { return returnCash; } public void setReturnCash(double returnCash) { this.returnCash = returnCash; } }
ChargeContext(处理收费的业务对象):
/** * 处理收费的Context (业务类) * @author Administrator * */ public class ChargeContext { /** * 收费接口 */ private Charge charge; /** * 收费传输对象 */ private ChargeFormDto dto; public ChargeContext(ChargeFormDto dto) { this.dto = dto; try { charge = (Charge) Class.forName(dto.getType()).newInstance(); } catch (Exception e) { e.printStackTrace(); } } /** * 返回收费结果 * @return */ public double account() { return charge.charge(dto); } }
ChargeClient(收费客户端):
public class ChargeClient { public static void main(String[] args) { // 创建收费清单 ChargeFormDto dto = new ChargeFormDto(); dto.setType("edu.strategy.strategy.impl.NormalCharge"); // 输入具体策略类的路径 dto.setPrice(300); // 创建收费服务 ChargeContext context = new ChargeContext(dto); // 计算 context.account(); } }
运行结果:
收费类型那里现在是写具体类名,但是这样不太方便,这里可以优化,可以选择读取配置文件与万能工厂的方式进行改进。
三、总结
优点:
1、易于扩展;策略模式提供了对 "开闭原则" 的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地新增新的算法或行为。
2、策略类之间可以自由切换;由于策略类都实现同一个接口,所有使它们间可以自由切换
3、解耦;将算法的责任和本身进行解耦,使得算法可独立使用外部而变化,客户端方法根据外部条件选择不同策略来解决不同的问题。
缺点:
1、客户端必须指定所有的策略类,并自行决定使用哪一个策略类。
2、策略模式将造成上次很多策略类。
适用性:
适用于动态选择多种负责行为:1、负责的算法/数据结构;2、类的行为/方法,提高行为的保密性。