行为参数化就是就是一个方法接受多个不同的行为作为参数,并在内部使用它们,完成
不同行为的能力。比如开车出去再回来,可以传入取邮件这个参数,也可以传入买东西这个参数。再比如查找方法:那么参数可以是筛选重量大于150的,也可以传入参数筛选绿色的,也可以传重量既大于150,还是绿色的。
为理解行为参数化,首先准备苹果类(自己写的,也不在乎好不好用,能用就行)。
public class Apple {
private String color;
private float weight;
enum Color
{
RED, GREEN, BLUE;
}
public Apple(String color, float weight) {
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public float getWeight() {
return weight;
}
public void setWeight(float weight) {
this.weight = weight;
}
/**
* 重写Apple类的toString
* @return
*/
@Override
public String toString() {
return "Apple{" +
"color='" + color + '\'' +
", weight=" + weight +
'}';
}
public static void main(String[] args){
//应该有个库存,这个库存里存着很多苹果
List<Apple> inventory = new ArrayList<>();
initInventor(inventory);//初始化农场库存
//使用遍历集合的方式取出绿色的苹果
System.out.println("使用遍历集合的方式取出绿色的苹果:"+"\n");
outInventor(filterGreenApples(inventory));
}
/**
* 初始化存储苹果的仓库
* @param inventory
*/
private static void initInventor(List<Apple> inventory){
Random r = new Random();
Color[] colors = Color.values();
for(int i = 0;i < 10; i++){
Apple apple = new Apple(colors[r.nextInt(2)].toString(),r.nextFloat()*1);
inventory.add(apple);
System.out.println(apple.toString());
}
}
/**
* 输出包含苹果的集合
* @param inventory
*/
private static void outInventor(List<Apple> inventory){
for(Apple apple:inventory){
System.out.println(apple.toString());
}
}
}
step1:要筛选绿色的苹果,最初的写法:
/**
* 普通的筛选绿色的苹果
* @param inventory
* @return
*/
public static List<Apple> filterGreenApples(List<Apple> inventory) {
List<Apple> result = new ArrayList<>(); //累积苹果的列表
for(Apple apple: inventory){
if( "GREEN".equals(apple.getColor() )) { //仅仅选出绿苹果
result.add(apple);
}
}
return result;
}
坏处就是如果你要是筛选红色的你还得定义一个 filterRedApples(List<Apple> inventory)的方法,或者你定义一个filterApplesByColor(List<Apple> inventory,String color)的方法
step2:使用策略
把策略(AppleGreenColorPredicate )传递给筛选方法:通过布尔表达式筛选封装在ApplePredicate对象内的苹果。
进一步的我们定义一个接口,再用类进行实现这个接口,在筛选方法中将这个接口对象作为参数,这样这个接口肯定有相应行为,这样就相当于将行为参数化了。具体实现为:
接口的定义为:
public interface ApplePredicate {
boolean test (Apple apple);
}
实现接口的类为:
public class AppleGreenColorPredicate implements ApplePredicate{
public boolean test(Apple apple){
return "GREEN".equals(apple.getColor());
}
}
利用接口进行筛选绿色苹果
public static List<Apple> filterApples(List<Apple> inventory,
ApplePredicate p){
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(p.test(apple)){ //谓词对象封装了测试苹果的条件
result.add(apple);
}
}
return result;
}
Main函数中调用为
System.out.println("使用接口的方式取出绿色的苹果:"+"\n");
List<Apple> greenApples = filterApples(inventory, new AppleGreenColorPredicate());
outInventor(greenApples);
唯一重要的代码是test方法的实现,正是它定义了filterApples方法的新行为。但令人遗憾的是,由于该filterApples方法只能接受对象,所以你必须把代码包裹在ApplePredicate对象里。你的做法就类似于在内联“传递代码”,因为你是通过一个实现了test方法的对象来传递布尔表达式的。
step3:使用匿名类
由于你为了实现一个接口而实体化了多个类,此时你可能会想到使用匿名内部类的方法来避免。
List<Apple> readApples = filterApples(inventory, new ApplePredicate() {
@Override
public boolean test(Apple apple) {
return "RED".equals(apple.getColor());
}
});
outInventor(readApples);
匿名类:同时声明并实例化一个类,允许你随用随建。改善了为一个接口声明多个实体类的问题。
缺点是占用空间大。
step4:使用lambda表达式
这是在实现了filterApples的基础上实现。
//使用lambda表达式
System.out.println("使用lambda表达式");
List<Apple> result = filterApples(inventory,(Apple apple)->"RED".equals(apple.getColor()) && 0.15 < apple.getWeight());
outInventor(result);
step5:将List类型抽象化
构建接口
public interface Predicate<T> {
boolean test(T t);
}
实现筛选方法
//注意Predicate<T>是个类啊,因为我们筛选也是筛选的随便的一个水果类
public static <T> List<T> filter(List<T> list ,Predicate<T> p){
List<T> result = new ArrayList<>();
for(T e:list){
if(p.test(e)){
result.add(e);
}
}
return result;
}
最后附上最终的代码:
Apple类
public class Apple {
private String color;
private double weight;
enum Color
{
RED, GREEN, BLUE;
}
public Apple(String color, double weight) {
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
/**
* 普通的筛选绿色的苹果
* @param inventory
* @return
*/
public static List<Apple> filterGreenApples(List<Apple> inventory) {
List<Apple> result = new ArrayList<>(); //累积苹果的列表
for(Apple apple: inventory){
if( "GREEN".equals(apple.getColor() )) { //仅仅选出绿苹果
result.add(apple);
}
}
return result;
}
//使用接口来筛选
public static List<Apple> filterApples(List<Apple> inventory,
ApplePredicate p){
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(p.test(apple)){ //谓词对象封装了测试苹果的条件
result.add(apple);
}
}
return result;
}
//注意Predicate<T>是个类啊,因为我们筛选也是筛选的随便的一个水果类
public static <T> List<T> filter(List<T> list ,Predicate<T> p){
List<T> result = new ArrayList<>();
for(T e:list){
if(p.test(e)){
result.add(e);
}
}
return result;
}
/**
* 重写Apple类的toString
* @return
*/
@Override
public String toString() {
return "Apple{" +
"color='" + color + '\'' +
", weight=" + weight +
'}';
}
public static void main(String[] args){
//应该有个库存,这个库存里存着很多苹果
List<Apple> inventory = new ArrayList<>();
initInventor(inventory);//初始化农场库存
//使用遍历集合的方式取出绿色的苹果
System.out.println("使用遍历集合的方式取出绿色的苹果:"+"\n");
outInventor(filterGreenApples(inventory));
//使用接口的方式取出绿色的苹果
System.out.println("使用接口的方式取出绿色的苹果:"+"\n");
List<Apple> greenApples = filterApples(inventory, new AppleGreenColorPredicate());
outInventor(greenApples);
//使用接口实现的最好的打印方法
prettyPrintApple(inventory, new AppleFancyFormatter());
//使用匿名类来取所有红色苹果
System.out.println("使用匿名类来取所有红色苹果");
List<Apple> readApples = filterApples(inventory, new ApplePredicate() {
@Override
public boolean test(Apple apple) {
return "RED".equals(apple.getColor());
}
});
outInventor(readApples);
//使用lambda表达式
System.out.println("使用lambda表达式");
List<Apple> result = filterApples(inventory,(Apple apple)->"RED".equals(apple.getColor()) && 0.15 < apple.getWeight());
outInventor(result);
//使用filter实现
System.out.println("使用filter实现");
result = filter(inventory,(Apple apple) -> "RED".equals(apple.getColor()));
outInventor(result);
}
/**
* 初始化存储苹果的仓库
* @param inventory
*/
private static void initInventor(List<Apple> inventory){
Random r = new Random();
Color[] colors = Color.values();
for(int i = 0;i < 10; i++){
Apple apple = new Apple(colors[r.nextInt(2)].toString(),r.nextDouble()*0.3);
inventory.add(apple);
System.out.println(apple.toString());
}
}
/**
* 输出包含苹果的集合
* @param inventory
*/
private static void outInventor(List<Apple> inventory){
for(Apple apple:inventory){
System.out.println(apple.toString());
}
}
public static void prettyPrintApple(List<Apple> inventory,
AppleFormatter formatter){
for(Apple apple: inventory){
String output = formatter.accept(apple);
System.out.println(output);
}
}
}
AppleFormatter接口:
public interface AppleFormatter {
String accept(Apple a);
}
Predicate接口:
public interface Predicate<T> {
boolean test(T t);
}
ApplePredicate接口
public interface ApplePredicate {
boolean test (Apple apple);
}
AppleFancyFormatter类
public class AppleFancyFormatter implements AppleFormatter{
public String accept(Apple apple){
String characteristic = apple.getWeight() > 0.15 ? "heavy" :
"light";
return "A " + characteristic +
" " + apple.getColor() +" apple";
}
}
AppleGreenColorPredicate实体类
public class AppleGreenColorPredicate implements ApplePredicate{
public boolean test(Apple apple){
return "GREEN".equals(apple.getColor());
}
}