如何建设营销型的网站,做seo的公司,seo推广软件下载,什么是网站建设方案书项目源码#xff1a;https://github.com/java8/
1 应对不断变化的需求
在我们进行开发中#xff0c;经常需要面临需求的不断变更#xff0c;我们可以将行为参数化以适应不断变更的需求。
行为参数化就是可以帮助我们处理频繁变更的需求的一种软件开发模式
我们可以将代码…项目源码https://github.com/java8/
1 应对不断变化的需求
在我们进行开发中经常需要面临需求的不断变更我们可以将行为参数化以适应不断变更的需求。
行为参数化就是可以帮助我们处理频繁变更的需求的一种软件开发模式
我们可以将代码块作为参数传递给方法。
例如现有一个仓库我们想定义从仓库中查询绿苹果的功能。后来我们又想查询重苹果150g…
面对这种不断变更的需求我们就可以使用行为参数化来维护我们的代码。
1.1 初试牛刀筛选出绿苹果
Apple类
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;Getter
Setter
AllArgsConstructor
ToString
public class Apple {private int weight 0;private String color ;
}// 初试牛刀筛选绿苹果
public static ListApple filterGreenApples(ListApple inventory) {ListApple result new ArrayList();for (Apple apple : inventory) {if (green.equals(apple.getColor())) {result.add(apple);}}return result;
} 如果说我们现在改变主意想要查询红色的苹果最简单的办法就是copy上面这个方法然后将方法改名为 fliterRedApples改变if 判断条件。谈若我们需要查询各种演示的苹果浅绿色、暗红色、黄色等那么再按照前面的这种方法来做代码将变得非常的冗余。
一个好的原则是尝试将我们上的的这个方法进行抽象化以适应不同颜色的苹果的查询。
下面我们进行尝试
1.2 再展身手把颜色作为参数
我们立马能想到的方法是将上面的 filterGreenApples 加上一个颜色参数就可以了
// 再展身手把颜色作为参数
public static ListApple filterApplesByColor(ListApple inventory, String color) {ListApple result new ArrayList();for (Apple apple : inventory) {if (apple.getColor().equals(color)) {result.add(apple);}}return result;
}这样我们就可以查询各种各样的苹果了如下
ListApple greenApple filterApplesByColor(inventory,green);
ListApple redApple filterApplesByColor(inventory,red);
...假设我们现在又要查询重苹果(150g)或轻苹果那么我们只需要根据
filterApplesByColor 进行稍稍修改即可如下
// 再展身手根据苹果的重量进行查询
public static ListApple filterApplesWeight(ListApple inventory, int weight) {ListApple result new ArrayList();for (Apple apple : inventory) {if (apple.getWeight() weight) {result.add(apple);}}return result;
}现在我们完成了根据颜色查询苹果、根据重量查询苹果的功能但是我们这两个方法极为相似复制了大部分的代码来实现遍历库存并对每个苹果应用筛选条件稍稍做了修改。
如果后续我们想改变查询的遍历方式来提升性能那么需要修改所有的方法这样显然是不合适的。
我们可以考虑将颜色和重量结合为一个方法称为filterApples。不过这样需要加上一个标记来区分是对什么属性颜色或重量的查询但是我们不推荐这种方式
1.3 第三次尝试对你能想到的每个属性做筛选
下面是一个比较笨拙的方法
// 生产环境别这么用
public static ListApple filterApples(ListApple inventory, String color,int weight, boolean flag) {ListApple result new ArrayList();for (Apple apple : inventory) {// 阅读性不好也很笨拙if (flag apple.getColor().equals(color) || !flag apple.getWeight() weight) {result.add(apple);}}return result;
}我们可以这样调用这个方法以使用不同属性的查询
// 根据颜色查询查询绿苹果
ListApple greenApples filterApples(inventory, green,0,true);
// 根据重量查询查询150g的重苹果
ListApple heavyApples filterApples(inventory,,150,false);这个方法能解决根据不同属性查询苹果的功能但是这样写代码很烂并且我们也不知道 boolean flag 参数传入 true、flase是什么意思可读性很差。
并且这样也不能很好的使用根据不同属性进行查询如果我们需要根据多个属性进行查询(比如查询绿色的重苹果)那更是天方夜谭了。
下面我们来解决这个问题
2 行为参数化
我们需要我们适应各种各样的属性来查询。
我们可以考虑根据Apple的属性来返回一个boolean值。我们把它称为谓词即一个返回boolean值的函数。下面我们定义一个接口来实现
// 判断型接口
FunctionalInterface
public interface ApplePredicate {boolean test(Apple apple);
}现在我们就可以用 ApplePredicate 的多个实现代表不同的查询标准了例如
// 查询出重苹果
public class AppleHeavyWeightPredicate implements ApplePredicate {Overridepublic boolean test(Apple apple) {return apple.getWeight() 150;}
}// 查询出绿苹果
public class AppleGreenColorPredicate implements ApplePredicate {Overridepublic boolean test(Apple apple) {return green.equals(apple.getColor());}
}我们可以把这些标准看作filter方法的不同行为。刚做的这些和“策略设计模式”相关它让你定义一族算法把它们封装起来称为“策略”然后在运行时选择一个算法。在这里算法族就是ApplePredicate不同的策略就是AppleHeavyWeightPredicate和AppleGreenColorPredicate。
但是该怎么利用ApplePredicate的不同实现呢
我们需要 filterApples方法接受 ApplePredicate对象对Apple做条件测试。这就是行为参数化让方法接受多种行为或战略作为参数并在内部使用来完成不同的行为。
个人对于行为参数化的理解
所谓行为参数化就是将行为一般封装成方法的形式以参数的形式传递到其他方法中执行。
如何实现行为参数化
我们要给filterApples方法添加一个参数让它接受 ApplePredicate对象。
行为参数化的好处
我们把filterApples方法迭代集合的逻辑与我们应用到集合中每个元素的行为这里是一个谓词即我们根据Apple的属性查询的行为区分开了。
2.1 第四次尝试根据抽象条件筛选
利用 ApplePredicate 修改后的 filter方法如下
public static ListApple filterApples(ListApple inventory, ApplePredicate predicate) {ListApple result new ArrayList();for (Apple apple : inventory) {if (predicate.test(apple)){ // 谓词对象封装了测试苹果的条件result.add(apple);}}return result;
}2.2 传递代码/行为
现在这段代码以及比我们前面写的方法灵活多了代码的可读性也高了。比如我们要查询红的重苹果只需要创建一个类实现现ApplePredicate接口即可甚至可以使用Lambda表达式
public class AppleRedAndHeavyPredicate implements ApplePredicate{Overridepublic boolean test(Apple apple) {return red.equals(apple.getColor()) apple.getWeight() 150;}
}// 调用
ListApple redAndHeavyApples filterApples(inventory, new AppleRedAndHeavyPredicate());现在我们的filterApples方法完成了行为参数化。
但是我们现在发现这样还是很麻烦我们要完成一个查询功能为此我们定义了一个类里面有一个方法完成对查询结果的判断这样有很多的无用代码代码可读性还是不高。
我们可以使用lmabda表达式简化不必要的代码直接把表达式red.equals(apple.getColor())
apple.getWeight() 150传递给filterApples方法无需定义一个类
// 使用Lambda表达式实现传递代码
ListApple redAndHeavyApples filterApples(inventory, (apple) -red.equals(apple.getColor()) apple.getWeight() 150);2.3 多种行为一个参数
行为参数化的好处在于你可以把迭代要筛选的集合的逻辑与对集合中每个元素应用的行为区分开来。这样你可以重复使用同一个方法给它不同的行为来达到不同的目的。
演示编写灵活的prettyPrintApple方法
编写一个prettyPrintApple方法它接受一个Apple的List并可以对它参数化以多种方式根据苹果生成一个String输出有点儿像多个可定制的toString方法。
例如你可以告诉 prettyPrintApple 方法只打印每个苹果的重量。此外你可以让 prettyPrintApple方法分别打印每个苹果然后说明它是重的还是轻的。
FunctionalInterface
public interface AppleFormatter{ String accept(Apple a);
}public class AppleFancyFormatter implements AppleFormatter { // 后续我们可以通过Lambda简化以省略这样的类public String accept(Apple apple) {String characteristic apple.getWeight() 150 ? heavy :light;return A characteristic apple.getColor() apple;}
}public class AppleSimpleFormatter implements AppleFormatter {public String accept(Apple apple) {return An apple of apple.getWeight() g;}
}public static void prettyPrintApple(ListApple inventory, AppleFormatter formatter) {for (Apple apple : inventory) {String output formatter.accept(apple);System.out.println(output);}
}使用
// 你首先要实例化AppleFormatter的实现然后把它们作为参数传给prettyPrintApple方法
prettyPrintApple(inventory, new AppleFancyFormatter());现在我们已经将行为抽象出来了这样使我们的代码适应不同的需求但是这样很繁琐
因为我们需要声明很多个只使用一次的类下面通过匿名内部类、Lambda表达式等方式进行简化
3 简化代码
在前面当要把新的行为传递给 filterApples方法的时候我们不得不声明好几个实现ApplePredicate接口的类然后实例化好几个只会提到一次的ApplePredicate对象。这真是很啰嗦很费时间
3.1 匿名类
匿名类和我们熟悉的 Java局部类块中定义的类差不多但匿名类没有名字。它允许我们同时声明并实例化一个类。换句话说它允许你随用随建
3.2 第五次尝试使用匿名类
下面我们将通过创建匿名类的方式实现ApplePredicate的对象重写筛选的例子以查询绿色苹果为例
ListApple greenApples filterApples(inventory, new ApplePredicate() { // 直接内联参数化filterapples方法的行为Overridepublic boolean test(Apple apple) {return red.equals(apple.getColor());}
});但是匿名类的方式还是不够好
它往往很笨重因为它占用了很多空间代码阅读性较差
总的来说使用匿名类的方式不仅代码编写、维护比较费时间可读性也不太好。
接下来我们使用Java 8中引人的Lambda表达式——一种更简洁的传递代码的方式。
3.3 第六次尝试使用 Lambda 表达式
使用Lambda表达式重写上面的代码
ListApple greenApples filterApples(inventory, (apple) -red.equals(apple.getColor()));到目前为止区别于以往的值参数传递我们已经实现了将类、匿名类、Lambda表达式等行为参数化传递到了方法中
3.4 第七次尝试将 List 类型抽象化
在通往抽象的路上我们还可以更进一步。目前filterApples方法还只适用于Apple。
我们还可以将List类型抽象化从而超越你眼前要处理的问题
FunctionalInterface
public interface PredicateT{ boolean test(T t);
}public static T ListT filter(ListT list, PredicateT p){ // 引入类型参数T即泛型ListT result new ArrayList(); for(T e: list){ if(p.test(e)){ result.add(e); } } return result;
} 现在我们的 filter 方法能更好的适应不同的查询了可以用在香蕉、桔子、Integer或是String的列表等等上了。
例如
ListApple redApples filter(inventory, (Apple apple) - red.equals(apple.getColor())); // 从numbers中筛选出偶数
ListInteger evenNumbers filter(numbers, (Integer i) - i % 2 0);4 真实的例子
到现在我们已经清除的知道了行为参数化是一个很有用的模式它能够轻松地适应不断变化的需求。这种模式可以把一个行为一段代码封装起来并通过传递和使用创建的行为例如对Apple的不同谓词将方法的行为参数化。前面提到过这种做法类似于策略设计模式。你可能已经在实践中用过这个模式了。Java API中的很多方法都可以用不同的行为来参数化。这些方法往往与匿名类一起使用。
我们会展示两个例子这应该能帮助你巩固传递代码的思想了用一个Comparator排序用Runnable执行一个代码块
4.1 用 Comparator 来排序
例如根据苹果的重量对库存进行排序或者希望你根据颜色对苹果进行排序。听起来有点儿耳熟是的
你需要一种方法来表示和使用不同的排序行为来轻松地适应变化的需求。
在Java 8中List自带了一个sort方法你也可以使用Collections.sort。sort的行为可以用java.util.Comparator对象来参数化如下
package java.util;FunctionalInterface
public interface ComparatorT {int compare(T o1, T o2);...
}因此我们可以随时创建Comparator的实现用sort方法表现出不同的行为。
比如你可以 使用匿名类按照苹果的重量升序对库存排序
inventory.sort(new ComparatorApple() {Overridepublic int compare(Apple o1, Apple o2) {return o1.getWeight() - o2.getWeight();}
});后续我们可以随时创建一个Comparator来满足新要求并把它传递给 sort方法。而如何进行排序这一内部细节都被抽象掉了。用Lambda表达式的话看起来就是这样
inventory.sort((Apple a1, Apple a2) - a1.getWeight() - a2.getWeight());4.2 用 Runnable 执行代码块
在 Java里你可以使用Runnable接口表示一个要执行的代码块
package java.lang;FunctionalInterface
public interface Runnable {public abstract void run();
}我们可以像下面这样使用这个接口创建执行不同行为的线程
Thread t new Thread(new Runnable() { Overridepublic void run(){ System.out.println(Hello world); }
}); 使用Lambda表达式简化
Thread t new Thread(() - System.out.println(Hello world)); 5 小结 行为参数化就是一个方法接受多个不同的行为作为参数并在内部使用它们完成不同行为的能力。 行为参数化可让代码更好地适应不断变化的要求减轻未来的工作量。 传递代码就是将新行为作为参数传递给方法。但在Java 8之前这实现起来很啰嗦。为接口声明许多只用一次的实体类而造成的啰嗦代码在Java 8之前可以用匿名类来减少。 Java API包含很多可以用不同行为进行参数化的方法包括排序、线程和GUI处理。