• 设计模式(十一)—— 策略模式


    一、定义:

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

    二、特点:

    • 环境类(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("支付异常");
            }
        }
    
  • 相关阅读:
    js中Math.random()生成指定范围数值的随机数【转】
    JS绘制生成花瓣效果的方法【转】
    php 解决json_encode中文UNICODE转码问题【转】
    JS/JQuery获取当前元素的上一个/下一个兄弟级元素等元素的方法【转】
    PHP数据类型转换(字符转数字,数字转字符)【转】
    PHP 数组转字符串,与字符串转数组【转】
    js中forEach,for in,for of循环的用法【转】
    layui下的checkbox用js如何选中它【转】
    js数组与字符串的相互转换方法【转】
    JS判断网页是否为手机打开【转】
  • 原文地址:https://www.cnblogs.com/fonxian/p/6091531.html
Copyright © 2020-2023  润新知