设计模式之策略模式

923 阅读3分钟
原文链接: facex.xyz

项目中遇到这样的一个需求:分别需要对发送的数据和接受的数据做编码和解码处理,且不同的设备编码和解码方式不同。一般写法是根据不同的设备选择相应的编码和解码方式。但是这种方法耦合性高,不易维护,增加设备的支持就需要修改原先的代码,这容易在原本正确的代码中引入新的错误,这也违背了开闭原则。对于这种情况,一种较好的解决方式就是策略模式。

转载请注明出处:www.facex.xyz,如有发现错误或有其他更好的实现方式可与我联系。

开闭原则:软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是对于修改是封闭的。

1. 策略模式的定义

策略模式定义了一系列算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而存在。

2. 策略模式的使用场景

  • 针对同一问题的多种处理方式,仅仅是具体行为有差别时。
  • 需要安全的封装多种同一类型的操作时。
  • 出现同一抽象类有多个子类,而又需要使用if-else或者switch-case来选择具体子类时。

4. UML类图

策略模式


5. 重构步骤

  1. 首先定义设备解码编码策略接口类:DeviceCodecStrategy,类中定义decode和encode两个虚拟方法。

    public interface DeviceCodecStrategy {
        /**
         * Author: www.facex.xyz
         * 解码
         */
        int decode(int data);
        /**
         * Author: www.facex.xyz
         * 编码
         */
        int encode(int data);
    }
  2. 定义设备A编码解码策略实现类:DeviceAStrategy,该类实现DeviceCodecStrategy接口。

    public class DeviceAStrategy implements DeviceCodecStrategy {
        @Override
        public int decode(int data) {
          /**
           * Author: www.facex.xyz
           * 设备A解码相关方法,这里将需要解码的信息-1
           */
            return data - 1;
        }
        @Override
        public int encode(int data) {
            /**
             * Author: www.facex.xyz
             * 设备A编码相关方法,这里将需要解码的信息+1
             */
            return data + 1;
        }
    }
  3. 定义角色类:DeviceCodec

    public class DeviceCodec {
        private DeviceCodecStrategy mStrategy;
        public void setStrategy(DeviceCodecStrategy strategy) {
            this.mStrategy = strategy;
        }
        public int decode(int data) {
            return mStrategy.decode(data);
        }
        public int encode(int data) {
            return mStrategy.encode(data);
        }
    }
  4. 使用策略模式

    public static void main(String[] args) {
        DeviceCodec deviceCodec = new DeviceCodec();
        /**
         * Author: www.facex.xyz
         * 设置解码编码策略
         */
        deviceCodec.setStrategy(new DeviceAStrategy());
        /**
         * Author: www.facex.xyz
         * 编码
         */
        System.out.println("设备A编码后:" + deviceCodec.encode(10));
        /**
         * Author: www.facex.xyz
         * 解码
         */
        System.out.println("设备A解码后:" + deviceCodec.decode(10));
     }

    输出结果如下,符合预期:

    设备A编码后:11

    设备A解码后:9

  5. 现在我们要支持新的DeviceB设备,同DeviceA,定义设备B编码解码策略实现类:DeviceBStrategy,实现DeviceCodecStrategy接口,使用方式同DeviceA。

    public class DeviceBStrategy implements DeviceCodecStrategy {
        @Override
        public int decode(int data) {
          /**
           * Author: www.facex.xyz
           * 设备B解码相关方法,这里将需要解码的信息-2
           */
            return data - 2;
        }
        @Override
        public int encode(int data) {
          /**
           * Author: www.facex.xyz
           * 设备B编码相关方法,这里将需要解码的信息+2
           */
            return data + 2;
        }
    }

6. 总结

使用策略模式重构代码后,隐藏了编码解码实现,同时可扩展性变强。以后新增加设备只需要实现DeviceCodecStrategy接口,重现decode和encode方法即可,不仅符合了开闭原则,而且逻辑性更强。

参考文献:《Android源码设计模式解析与实战》