zoukankan      html  css  js  c++  java
  • 设计模式(十一)—— 策略模式

    一、定义:

    定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

    二、特点:

    • 环境类(Context):用一个ConcreteStrategy对象来配置。维护一个对Strategy对象的引用。可定义一个接口来让Strategy访问它的数据。
    • 抽象策略类(Strategy):定义所有支持的算法的公共接口。 Context使用这个接口来调用某ConcreteStrategy定义的算法。
    • 具体策略类(ConcreteStrategy):以Strategy接口实现某具体算法。

    三、情景:

    设计一个鸭子,会有很多种不同的鸭子,比如说白头鸭、黑头鸭、橡皮鸭、木头鸭等等,这些鸭,有的会叫,有的不会,有的会飞,有的不会,但每一个鸭都会游泳。让你来设计要怎么设计。

    设计一:最差的方法

    有多少只鸭就建多少个类,这样重复性的工作量太大,代码会十分的难看

    设计二:稍微好一点的方法

    对这些鸭抽象一下,比如说所有的鸭都会游泳,就创建一个抽象类,类中实现了游泳的方法。
    其他的叫、飞等行为写在每个鸭的实现类中。

    设计三:再优化一点的方法

    把叫和飞这两种行为再抽象出来,形成两个接口,每个鸭都要继承抽象鸭,并且实现飞和叫这两种接口。
    但这样有一个问题,有些鸭其实都可以叫的,而且叫的方式都一毛一样。如果每个都这么写得话,也会带来挺大的工作量,所以还需要再进一步优化

    设计四:最终优化

    将叫和飞两种行为接口,作为实例放到抽象鸭的类中,使用面向接口的方式来实现

    抽象鸭类

    public abstract class Duck {
        
        FlyBehavior flyBehavior;
        JiaoBehavior jiaoBehavior;
    
        .........
    }
    

    鸭会飞行为实现类

    public class CanFly implements FlyBehavior
    {
    
    
    }
    

    某具体的种类的鸭

    public class ZhouHeiDuck extends Duck{
        public ZhouHeiDuck(){
            flyBehavior = new CanFly();
        }
    }
    

    总结

    上面的例子很具有代表性。也反映了设计的两个原则:

    1、需要改变的东西和不需要改变的东西要分离开,确切的说,应该要将会改变的东西独立出来

    2、针对于接口编程而不是针对于实现编程

    应用场景

    使用注解实现对支付方式的策略封装

    定义注解

    
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface PayType {
    
        String desc();
    
        PayTypeEnum type();
    
    }
    
    

    定义枚举类

    public enum  PayTypeEnum {
    
        ALIPAY(1),
        WECHAT(2);
    
        PayTypeEnum(int type) {
            this.type = type;
        }
    
        private int type;
    
        public int getType() {
            return type;
        }
    
        public void setType(int type) {
            this.type = type;
        }
    
    }
    

    定义接口与实现类

    public interface IPayService {
        String pay(BigDecimal amount);
    }
    
    @Service
    @PayType(desc = "微信支付", type = PayTypeEnum.WECHAT)
    public class WechatPayService implements IPayService {
    
        @Override
        public String pay(BigDecimal amount) {
            System.out.println("微信到帐{}元!" + amount);
            return "success";
        }
    
    }
    
    @Service
    @PayType(desc = "支付宝支付",type = PayTypeEnum.ALIPAY)
    public class AlipayPayService implements IPayService{
    
        @Override
        public String pay(BigDecimal amount) {
            System.out.println("支付宝到帐{}元!"+amount);
            return "success";
        }
    
    }
    

    网关类

    @Service
    public class PayGateWayService {
    
        @Autowired
        private List<IPayService> payServiceList;
    
        public IPayService route(int type) throws Exception {
            for (IPayService payService : payServiceList) {
                PayType payTypeAnnotation = payService.getClass().getAnnotation(PayType.class);
                if (payTypeAnnotation.type().getType() == type) {
                    System.out.println("路由到具体的支付业务类为:" + payService.getClass().getSimpleName());
                    return payService;
                }
            }
            throw new Exception("没有找到具体支付业务类");
        }
    
    }
    

    测试类

        @Test
        public void test() {
            int type = PayTypeEnum.WECHAT.getType();//支付宝支付
            BigDecimal amount = BigDecimal.valueOf(100);//支付金额 100 元
            IPayService payService = null;//支付网关类
            try {
                payService = payGateWayService.route(type);
                payService.pay(amount);//开始支付
            } catch (Exception e) {
                System.out.println("支付异常");
            }
        }
    
  • 相关阅读:
    SQL SERVER使用技巧集
    WIN32串口编程
    经典FLASH收藏
    Windows下WinsockAPI研究
    数据库连接大全[转自中国站长网]
    VirtualBox自动重启之谜
    写个设置命令的VBS脚本工具。
    VB中KeyCode的取法
    实现串口编程的三种方法
    .NET的命名空间
  • 原文地址:https://www.cnblogs.com/fonxian/p/6091531.html
Copyright © 2011-2022 走看看