ASP源码.NET源码PHP源码JSP源码JAVA源码DELPHI源码PB源码VC源码VB源码Android源码
当前位置:首页 >> 软件工程 >> 反馈法学习设计模式一——策略模式Strategy Pattern

反馈法学习设计模式一——策略模式Strategy Pattern(1/2)

来源:网络整理     时间:2017-11-08     关键词:

本篇文章主要介绍了" 反馈法学习设计模式一——策略模式Strategy Pattern",主要涉及到方面的内容,对于软件工程感兴趣的同学可以参考一下: 简介(Introduction) 之前学习Java8实战时,遇到一个很好的策略模式示例。便想着借着这个示例结合反馈式的方法来,学习策略设计模式,也以便后面反复琢...

简介(Introduction)

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

练习

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

策略模式(Strategy Pattern)

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

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

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

UML

 反馈法学习设计模式一——策略模式Strategy Pattern

代码实现

  • 代码目录结构
     反馈法学习设计模式一——策略模式Strategy Pattern

  • 核心代码,具体详见github

package Demo.filter;//// 该类用于筛选苹果// 代码质量要求:更加抽象通用, 更加简洁// 以下七次的代码修改也相应反映代码的质量及水平//// Created by auhnayuil on 17-9-24.//publicclass FilterApple implements Filter {

    //// 第一次需求:选取绿色苹果// 该方法纯粹为筛选出绿色苹果// 筛选苹果的条件为常量, 很难适应客户或者调用者的需求变化//public Set filterGreenApple(Set apples){
        Set result = new HashSet<>();
        for(Apple apple : apples){
            if("green".equals(apple.getColor()))
                result.add(apple);
        }
        return result;
    }

    //// 第二次需求变化:能够选取各种颜色的苹果// 将颜色提取为方法的参数, 更灵活地适应筛选各种颜色的苹果//// 一个良好的原则是在编写某个需求多变的代码时, 尝试将其抽象化///public Set filterAppleByColor(Set apples, String color){
        Set result = new HashSet<>();
        for(Apple apple : apples){
            if(apple.getColor().equals(color))
                result.add(apple);
        }
        return result;
    }

    //// 第三次需求变化:能够筛选各种颜色, 各种重量的苹果// 需求变化的因素除了单一元素上变化, 还表现为多元素上变化//// 一旦多属性被要求组合查询, 进行更复杂的查询时// 筛选条件及使用上将会变得非常笨拙及丑陋///public Set filterApples(Set apples, String color, Float weight){
        Set 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 filterApples(List apples, Predicate predicate){
        return (List) collect(apples, predicate);
    }

    //// 第五尝试:匿名类// 没有变量名, 允许你同时声明并实例化一个类/////public Set filterApplesByAnonymousClass(Set apples){
        return (Set) collect(apples, new Predicate() {
            @Overridepublicbooleantest(Apple target) {
                return ("red".equals(target.getColor()) && target.getWeight() > 0.0F);
            }
        });
    }

    ////  第六次尝试:Lambda表达式 以及 抽象结果集//  可以改写为以下形式://  filterApplesByLambda(apples, (Apple apple) -> "red".equals(apple.getColor()));////  那么如何用Lambda改写一个内部类?//public Set filterApplesByLambda(Collection apples, boolean is){
        Set result = new HashSet<>();
        for(Apple apple : apples){
            if(is)
                result.add(apple);
        }
        return result;
    }
}

相关图片

相关文章