zoukankan      html  css  js  c++  java
  • 反馈法学习设计模式(一)——策略模式Strategy Pattern

    简介(Introduction)

    之前学习Java8实战时,遇到一个很好的策略模式示例。便想着借着这个示例结合反馈式的方法来,学习策略设计模式,也以便后面反复琢磨学习。
    首先我们通过练习,逐步写出符合相应需求的代码,再根据需求进行改进、比较、重写,最终得出一种更灵活的最佳实现。

    练习

        /** 该类为苹果 */
        class Apple {
            private Float weight;
            private String color;
        }
        /** 该类为苹果过滤器 */
        public class AppleFilter {
            private Set<Apple> apples;
        }
    
    • 需求一,添加方法使得可以筛选绿苹果
    • 需求二,能够选取各种颜色的苹果
    • 需求三,能够筛选各种颜色, 各种重量的苹果
    • 需求四,将筛选条件进行抽象,能筛选各种属性
    • 需求五,使用匿名类进行改进

    策略模式(Strategy Pattern)

    对于策略模式,我的理解是行为参数化。行为是指处理频繁变化需求的那段代码。每当需求变化时,就传递不同的行为作为参数进行处理。如此,便是将代码块进行封装,得到可进行应对变化的策略一般。

    策略模式,它定义了算法家族。分别封装起来,让它们之间可以相互替换,此模式让算法的变换,不会影响到使用算法的客户端。——《设计模式:可复用面向对象软件的基础》

    • 解决什么矛盾:不同时间应用不同的业务规则;多重条件判断、硬编码所带来的复杂及难以维护
    • 如何用代码实现:每个策略,实现约定的接口及方法。
    • 优点:耦合性低(降低各种策略类与调用者的耦合)、扩展性强、代码简洁(策略封装了变化的条件、避免了多重判断)
    • 缺点:策略类膨胀、代码繁琐

    UML

    策略模式.PNG

    代码实现

    package Demo.filter;
    
    //
    // 该类用于筛选苹果
    // 代码质量要求:更加抽象通用, 更加简洁
    // 以下七次的代码修改也相应反映代码的质量及水平
    //
    // Created by auhnayuil on 17-9-24.
    //
    public class FilterApple implements Filter<Apple> {
    
        //
        // 第一次需求:选取绿色苹果
        // 该方法纯粹为筛选出绿色苹果
        // 筛选苹果的条件为常量, 很难适应客户或者调用者的需求变化
        //
        public Set<Apple> filterGreenApple(Set<Apple> apples){
            Set<Apple> result = new HashSet<>();
            for(Apple apple : apples){
                if("green".equals(apple.getColor()))
                    result.add(apple);
            }
            return result;
        }
    
        //
        // 第二次需求变化:能够选取各种颜色的苹果
        // 将颜色提取为方法的参数, 更灵活地适应筛选各种颜色的苹果
        //
        // 一个良好的原则是在编写某个需求多变的代码时, 尝试将其抽象化
        ///
        public Set<Apple> filterAppleByColor(Set<Apple> apples, String color){
            Set<Apple> result = new HashSet<>();
            for(Apple apple : apples){
                if(apple.getColor().equals(color))
                    result.add(apple);
            }
            return result;
        }
    
        //
        // 第三次需求变化:能够筛选各种颜色, 各种重量的苹果
        // 需求变化的因素除了单一元素上变化, 还表现为多元素上变化
        //
        // 一旦多属性被要求组合查询, 进行更复杂的查询时
        // 筛选条件及使用上将会变得非常笨拙及丑陋
        ///
        public Set<Apple> filterApples(Set<Apple> apples, String color, Float weight){
            Set<Apple> result = new HashSet<>();
            for(Apple apple : apples){
                if(     apple.getColor().equals(color)
                        && apple.getWeight() > weight)
                    result.add(apple);
            }
            return result;
        }
    
        //
        // 第四次尝试:将筛选条件进行抽象, 将行为参数化
        // 更高层次的抽象为将选择条件进行建模, 即形成一种可进行选择的通用的策略
        //
        // 模型描述:根据对象的某些属性来返回一个布尔值
        // 类似于"谓词"这样的语义
        //
        // 至于为何要在方法参数中抽象筛选条件为一个接口?
        //
        // 到这里, filterApples的行为仅取决于 Predicate对象所传递的代码, 也就是
        // 所谓的 向一个参数传递了代码, 或者行为参数化了
        //
        // 值需要创建包裹着不同筛选条件的代码块 的Predicate对象就可以实现不同的行为了
        ///
        public List<Apple> filterApples(List<Apple> apples, Predicate<Apple> predicate){
            return (List<Apple>) collect(apples, predicate);
        }
    
        //
        // 第五尝试:匿名类
        // 没有变量名, 允许你同时声明并实例化一个类
        //
        ///
        public Set<Apple> filterApplesByAnonymousClass(Set<Apple> apples){
            return (Set<Apple>) collect(apples, new Predicate<Apple>() {
                @Override
                public boolean test(Apple target) {
                    return ("red".equals(target.getColor()) && target.getWeight() > 0.0F);
                }
            });
        }
    
        //
        //  第六次尝试:Lambda表达式 以及 抽象结果集
        //  可以改写为以下形式:
        //  filterApplesByLambda(apples, (Apple apple) -> "red".equals(apple.getColor()));
        //
        //  那么如何用Lambda改写一个内部类?
        //
        public Set<Apple> filterApplesByLambda(Collection<Apple> apples, boolean is){
            Set<Apple> result = new HashSet<>();
            for(Apple apple : apples){
                if(is)
                    result.add(apple);
            }
            return result;
        }
    }
    
    
    package Demo.filter;
    
    //
    // 该方法为最基本的过滤器
    // 用于抽象各个过滤器中的循环, 遍历, 收集等重复行为
    // 采用接口的默认方法实现
    //
    // Created by auhnayuil on 17-9-24.
    //
    public interface Filter<T> {
    
        default Collection<T> collect(Collection<T> targets, Predicate<T> predicate) {
            Class<? extends Collection> clazz = targets.getClass();
            Collection result = null;
            try {
                 //该部分代码块, 通过反射生成集合的实例对象. 得到一个空的结果集对象
                 result = clazz.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
    
            for(T target : targets){
                //循环遍历目标集合, 并且通过接口形成策略判断是否符合过滤器条件
                //收集符合条件的结果
                if(predicate.test(target))
                    result.add(target);
            }
            return result;
        }
    }
    
    package Demo.predicate;
    
    //
    // 策略设计模式(Staregy)
    // 定义了一系列的算法族, 并将其封装, 可以相互替换且在运行时选择所需要的合适的"策略"
    // Created by auhnayuil on 17-9-24.
    //
    public class AppleRedAndWeightPrdicate implements Predicate<Apple> {
    
        @Override
        public boolean test(Apple target) {
            return ("red".equals(target.getColor())
                    && target.getWeight() > 0.0F);
        }
    }
    

    参考链接

    [Java8实战] https://book.douban.com/subject/26772632/
    [Baidu] https://baike.baidu.com/item/策略模式/646307?fr=aladdin
    [菜鸟教程] http://www.runoob.com/design-pattern/strategy-pattern.html

  • 相关阅读:
    python daemon install
    添加 sudoer centos
    CentOS 5安装openssh
    java使用sh或是jsvc来做daemon应该是主流
    Maven JAR Plugin
    The Java™ Tutorials offical学习的好资料哦
    linux下lrzsz安装,SecureCRT上传下载文件工具 寒枫欣叶
    ssh on centos5
    CentOS Linux Install Core Development Tools Automake, Gcc (C/C++), Perl, Python & Debuggers
    Setting an Application's Entry Point
  • 原文地址:https://www.cnblogs.com/chenjunping/p/7788629.html
Copyright © 2011-2022 走看看