zoukankan      html  css  js  c++  java
  • 设计模式学习笔记(三)——策略模式

    一、概述

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

      策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以互相替换。在策略模式中,调用算法的主体是封装到了封装类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、类的行为/方法,提高行为的保密性。

  • 相关阅读:
    python安装教程
    protobuf安装教程
    PlantUML安装教程
    题解-CF1140E Palindrome-less Arrays
    FST
    线段树
    题解-CF677D Vanya and Treasure
    最短路
    后缀自动机
    虚树
  • 原文地址:https://www.cnblogs.com/hejianliang/p/9154921.html
Copyright © 2011-2022 走看看