zoukankan      html  css  js  c++  java
  • 利用策略模式消除分支

    在实际的开发过程中,我们经常会遇到对于不同的对象采用不同的算法或者策略的场景。

    一个真实的例子是这样的:

    假设现在要将一个Student对象存入数据库。在逻辑层,需要对对象的字段进行合法性判断,比如ID是否超过某个阈值,名字长度是否超长。

     1 public class Student {
     2     
     3     private Integer id;
     4     
     5     private String name;
     6     
     7     public Integer getId() {
     8         return id;
     9     }
    10 
    11     public void setId(Integer id) {
    12         this.id = id;
    13     }
    14 
    15     public String getFirstName() {
    16         return name;
    17     }
    18 
    19     public void setFirstName(String firstName) {
    20         this.name = firstName;
    21     }
    22 }

    1. if else分支方法

    最常见的做法,是将参数的类型进行分类。提供一个方法,对传入的参数,根据不同的参数类型进行校验。

    package com.huawei.khlin.strategy;
    
    public class App {
    
        public static void validateField(Object param, FieldType type)
                throws Exception {
            if (type == FieldType.INTEGER) {
                // do something....
            } else if (type == FieldType.DOUBLE) {
                // do something....
            } else if (type == FieldType.CHAR) {
                // do something....
            } else if (type == FieldType.STRING) {
                // do something...
            }
        }
    
        public static enum FieldType {
            INTEGER, DOUBLE, CHAR, STRING;
        }
        
        public static void main(String[] args) throws Exception {
            Student student = new Student();
            student.setId(Integer.valueOf(1));
            student.setName("kingsley");
            
            validateField(student.getId(), FieldType.INTEGER);
            validateField(student.getName(), FieldType.STRING);
            
            //dao层操作
        }
    }

    上面的if else分支换成switch效果是一样的。

    可以预见的是,当字段的类型越来越多(包括同样类型但阈值不同,例如String 32长度和64长度),validateField方法将会越来越臃肿,分支数量分分钟超过最大圈复杂度15.

    2. 策略模式拯救烂代码

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

    个人理解,策略模式实际上就是利用了类的多态性,通过不同的实现类,在不同的场景下使用不同的算法处理事务。

    那么,什么时候就要使用策略模式呢?我认为,当某个算法比较复杂,并且你头脑里第一个闪现的想法是用if else来做分支处理,那么就是使用策略模式的时候。

    策略模式的结构图如下:

    主要有三个组件

    Context:持有Strategy对象

    Stragety: 抽象的策略类,提供统一的操作方法

    ConcretStrategy:具体的策略类,封装了一些行为或算法

    具体到上述的场景中,Context就是调用的客户端,即main方法。而根据不同的类型进行参数校验,则是不同的ConcreteStrategy.

    这样,我们的代码就可以改成如下:

    抽象的策略类

    1 public interface Validator {
    2     
    3     public void validate(Object value) throws Exception;
    4 
    5 }

    具体的策略类

     1 public class IntegerValidator implements Validator {
     2 
     3     private int maxCount = Integer.MAX_VALUE;
     4 
     5     private int minCount = 0;
     6 
     7     public IntegerValidator() {
     8 
     9     }
    10 
    11     public IntegerValidator(int minCount, int maxCount) {
    12         this.minCount = minCount;
    13         this.maxCount = maxCount;
    14     }
    15 
    16     @Override
    17     public void validate(Object value) throws Exception {
    18 
    19         int realValue = 0;
    20 
    21         if (null == value) {
    22 
    23             realValue = 0;
    24 
    25         } else {
    26             if (!(value instanceof Integer)) {
    27                 throw new Exception("field is NOT String Type.");
    28             }
    29 
    30             Integer valueInteger = Integer.valueOf(value.toString());
    31 
    32             realValue = valueInteger.intValue();
    33 
    34         }
    35 
    36         if (!(realValue >= minCount && realValue <= maxCount)) {
    37             throw new Exception("integer value out of range.");
    38         }
    39     }
    40 
    41 }
     1 public class StringValidator implements Validator {
     2     
     3     private int maxCount = 1024;
     4 
     5     private int minCount = 0;
     6 
     7     public StringValidator() {
     8 
     9     }
    10 
    11     public StringValidator(int minCount, int maxCount) {
    12         this.minCount = minCount;
    13         this.maxCount = maxCount;
    14     }
    15 
    16     @Override
    17     public void validate(Object value) throws Exception {
    18         int charNumber = 0;
    19 
    20         if (null == value) {
    21             
    22             charNumber = 0;
    23             
    24         } else {
    25             if (!(value instanceof String)) {
    26                 throw new Exception("field is NOT String Type.");
    27             }
    28 
    29             String valueStr = (String) value;
    30 
    31             charNumber = valueStr.length();
    32 
    33         }
    34         
    35         if(!(charNumber >= minCount && charNumber <= maxCount)) {
    36             throw new Exception("value out of range.");
    37         }
    38 
    39     }
    40 }

    Context环境

     1 public class ValidatorContext {
     2     
     3     private Validator validator;
     4     
     5     public ValidatorContext(Validator validator) {
     6         this.validator = validator;
     7     }
     8     
     9     public void operate(Object param) throws Exception {
    10         validator.validate(param);
    11     }
    12 }

    main方法调用

     1 public class App {
     2 
     3     private static final Validator DEFAULT_STRING_VALIDATOR = new StringValidator(0, 1024);
     4     
     5     private static final Validator DEFAULT_INTEGER_VALIDATOR = new IntegerValidator(0, 100);
     6     
     7     public static void main(String[] args) throws Exception {
     8         Student student = new Student();
     9         student.setId(Integer.valueOf(1));
    10         student.setName("kingsley");
    11         
    12         ValidatorContext idContext = new ValidatorContext(DEFAULT_INTEGER_VALIDATOR);
    13         ValidatorContext nameContext = new ValidatorContext(DEFAULT_STRING_VALIDATOR);
    14         
    15         idContext.validate(student.getId());
    16         nameContext.validate(student.getName());
    17         // dao层操作
    18     }
    19 }

    策略模式的优点是可以动态地改变对应的算法,并且在算法扩展时,可以不修改原有代码,而扩展出新的算法(即符合开闭原则)。同时可以有效地减少多条分支的判断,增加代码可读性。

    缺点是会产生比较多的策略类,并且客户端需要知道都有哪些策略。

  • 相关阅读:
    动态规划突破
    日志如何进行处理
    多线程相关问题
    Activity工作流框架
    修改模块
    spring多模块搭建Eureka服务器端
    springcould多模块搭建Eureka的服务器端口
    java操作elecsearch
    在elementui和MyBatis中前后端分离中使用shiro
    elementui的和前后端分离的微信登陆功能
  • 原文地址:https://www.cnblogs.com/kingsleylam/p/6671052.html
Copyright © 2011-2022 走看看