设计模式学习笔记(三)——策略模式

一、概述

  策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们之间可以互相替换。策略模式使得算法可以在不影响客户端的情况下发生变化。

  策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以互相替换。在策略模式中,调用算法的主体是封装到了封装类Context中,抽象策略Strategy一般是一个接口,目的只是为了定义规范,里面一般不包含逻辑。其实,这只是通用实现,而在实际编程中,因为各个具体策略实现类之间难免存在一些相同的逻辑,为了避免重复的代码,我们常常使用抽象类来担任Strategy的角色,在里面封装公共的代码。

二、实现策略模式

  需求:

  收费系统
  分别有三种收费方式:
  ①正常收费
  ②打折收费
  ③返利收费
 
  客户端发送(参数)到业务层,判断参数属于哪种收费模式,然后进行收费.
 
  要求:用到单一设计原则,开闭原则.
 
  ====================================================================
  分析:
  收费有各种收费方式,那么可以将收费抽象出来,定义一个接口,以后出现哪种收费的时候,就实现收费接口.
  
   Charge(收费接口):定义一个抽象收费接口,让子类去实现它。
  NormalCharge(正常收费):实现收费接口,定义具体的收费算法;具体策略类。
  DiscountCharge(打折收费):实现收费接口, 定义具体的收费算法;具体策略类。
  RebateCharge(返利收费):实现收费接口, 定义具体的收费算法;具体策略类。
  ChargeFormDto(收费传输对象):负责传输收费所需的参数,封装客户端传输的参数,有收费类型、总价、折扣、满额度、返额度。
  ChargeContext(处理收费的业务对象):负责收费调用的业务,调用具体收费策略、计算。
  ChargeClient(收费客户端):收费客户端。
 
  Charge(收费接口):
/**
 * 收费接口
 * @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、类的行为/方法,提高行为的保密性。

原文地址:https://www.cnblogs.com/hejianliang/p/9154921.html