【版本任你发】-4-行为参数化

153 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情

0.背景

  上一讲讲完了,其实有一点没有提到。就是 Predicate (断言) 的出现,主要是因为编程里面的一个概念——行为参数化。

  行为参数化,到底是新概念,还是新壶装旧酒?我们今天,依据一篇老外写的文章:Behavior Parameterization 来一探究竟。

1.帮助你封装那些相似的代码

Behavior parameterization is the ability of a method to receive multiple different behavior as its parameter and use them internally to accomplish the task. It let you to make your code more adaptive to changing requirements and saves the engineering effort from writing similar piece of code here and there.

  这一段,主要就是说,可以让主体的作为流程控制的代码保持不动,细枝末节的业务流程代码可以随时用传递方法一样的方式来适应变动的需求,这对封装相似的代码大有裨益。

If you have come across some of the behavioral design patterns like Strategy Pattern then you know we create set of similar algorithms and choose required one at run time to deal with a certain problem scenario. This type of techniques facilitate to add new behaviors in future. Let’s look into a problem statement to understand better.

  这里说了 策略模式 ,策略模式可以在代码运行的时候根据实际对象的参数实际的值来运行不同的方法。行为参数化的逻辑和策略模式类似。这里呢,我赋诗一首:

田忌齐王比赛马,胜利两次是赢家。 每次赛马走策略,先出下马再上马。 虽是每次都赛马,每场派了不同马。 策略懂得思全局,临界条件必审查。

2.写一个传递策略实现类的例子

  原文中又给出了一个公司准备基于各种指标给人分组的例子。先是创建了一个分组接口,然后实现了各种分组的规则策略类,最后使用这些规则。

 interface Groupable {
     public String findGroup(Employee e);
 }

 class GroupByExperience implements Groupable {

     @Override
     public String findGroup(Employee e) {
         return e.yearsOfExpr >= 7 ? "Expert" :
             e.yearsOfExpr >= 3 ? "Intermediet" : "Fresher";
     }
 }

 class GroupByTechnology implements Groupable {

     @Override
     public String findGroup(Employee e) {
         Map<String, List<String>> mapping = new HashMap<String, List<String>>() {
             {
                 put("Front-end", Arrays.asList("AngularJS", "ExtJS"));
                 put("Middleware", Arrays.asList("Java", ".Net"));
                 put("Back-end", Arrays.asList("Oracle", "MySQL", "PostgreSQL"));
             }
         };

         for (Entry<String, List<String>> entry : mapping.entrySet()) {
             if (entry.getValue().contains(e.technology)) {
                 return entry.getKey();
             }
         }
         // 这里是好的示范,一定要考虑例外的情况。
         return "Others";
     }
 }

  使用的时候,形参写接口即可。

public Map<String, List<String>> group(List<Employee> list, Groupable behavior) {
    Map<String, List<String>> map = new HashMap<>();
    for (Employee e : list) {
        String group = behavior.findGroup(e);
        map.putIfAbsent(group, new ArrayList<>());
        map.get(group).add(e.name);
    }
    return map;
}

  这样呢,不同的行为就放到具体的实现类里了。

结语

  本文和首篇文章讲 传递函数 的那一节,略有不同。本文是从考虑实现 多态 出发,设计接口,然后在业务代码中传递接口的实现类,从而实现行为的参数化。虽然实现起来很像,但是出发点略有不同。

  在此,我们也稍微复习一下多态,什么是编程中的多态呢?抛开编程语言,多态 最好的理解是:

在编程语言和类型论中,多态(英语:polymorphism )指为不同数据类型的实体提供统一的接口,或使用一个单一的符号来表示多个不同的类型。

  多态在实际的编程语言实现中,大体上抽象为此三类:

  1. 特设多态:为个体的特定类型的任意集合定义一个共同接口。
  2. 参数多态:指定一个或多个类型不靠名字而是靠可以标识任何类型的抽象符号。
  3. 子类型(也叫做子类型多态或包含多态):一个名字指称很多不同的类的实例,这些类有某个共同的超类。

  我们说具体一点:

多态类型具体应用
特设多态函数重载/运算符重载(想想 C++ 的重载运算符)
参数多态泛型
子类型多态继承与实现接口

好了,今天的内容到此也就结束了。你有什么想要和其他读者交流的呢?欢迎你在评论区留下你的看法,我们下期再见。