使用 Lambda 重构面向对象的设计模式

1. 策略模式

策略模式代表了解决一类算法的通用解决方案,你可以在运行时选择使用哪种方案。(比如苹果的重量,或者颜色)来筛选库存中的苹果。
策略模式包含三部分内容:

  • 一个代表某个算法的接口(它是策略模式的接口)。
  • 一个或多个该接口的具体实现,它们代表了算法的多种实现(比如,实体类ConcreteStrategyA或者ConcreteStrategyB)。
  • 一个或多个使用策略对象的客户。
    在这里插入图片描述
//我们假设你希望验证输入的内容是否根据标准进行了恰当的格式化(比如只包含小写字母或数字)。
//你可以从定义一个验证文本(以String的形式表示)的接口入手:
public interface ValidationStrategy { 
 boolean execute(String s); 
} 
//其次,你定义了该接口的一个或多个具体实现:
public class IsAllLowerCase implements ValidationStrategy { 
 public boolean execute(String s){ 
 return s.matches("[a-z]+"); 
 } 
} 
public class IsNumeric implements ValidationStrategy { 
 public boolean execute(String s){ 
 return s.matches("\\d+"); 
 } 
} 
//之后,你就可以在你的程序中使用这些略有差异的验证策略了:
public class Validator{ 
 private final ValidationStrategy strategy; 
 public Validator(ValidationStrategy v){ 
 this.strategy = v;
 } 
 public boolean validate(String s){ 
 return strategy.execute(s); 
 } 
} 


Validator numericValidator = new Validator(new IsNumeric()); 
boolean b1 = numericValidator.validate("aaaa"); 

Validator lowerCaseValidator = new Validator(new IsAllLowerCase ()); 
boolean b2 = lowerCaseValidator.validate("bbbb");

//使用Lambda表达式
//到现在为止,你应该已经意识到ValidationStrategy是一个函数接口了(除此之外,它还与Predicate具有同样的函数描述)。
//这意味着我们不需要声明新的类来实现不同的策略,通过直接传递Lambda表达式就能达到同样的目的,并且还更简洁:
Validator numericValidator = new Validator((String s) -> s.matches("[a-z]+")); 
 boolean b1 = numericValidator.validate("aaaa"); 

Validator lowerCaseValidator = new Validator((String s) -> s.matches("\\d+")); 
boolean b2 = lowerCaseValidator.validate("bbbb");

2.模板方法

模板方法模式在你“希望使用这个算法,但是需要对其中的某些行进行改进,才能达到希望的效果”时是非常有用的。

//假设你需要编写一个简单的在线银行应用。通常,用户需要输入一个用户账户,之后应用才能从银行的数据库中得到用户的详细信息,最终完成一些让用户满意的操作。
//不同分行的在线银行应用让客户满意的方式可能还略有不同,比如给客户的账户发放红利,或者仅仅是少发送一些推广文件。

//你可能通过下面的抽象类方式来实现在线银行应用:
abstract class OnlineBanking { 
   public void processCustomer(int id){ 
   	  Customer c = Database.getCustomerWithId(id); 
 	  makeCustomerHappy(c); 
   }
   abstract void makeCustomerHappy(Customer c); 
}

//processCustomer方法搭建了在线银行算法的框架:获取客户提供的ID,然后提供服务让用户满意。
//不同的支行可以通过继承OnlineBanking类,对该方法提供差异化的实现。

//使用Lambda表达式
//这里我们向processCustomer方法引入了第二个参数,它是一个Consumer类型的参数,
//与前文定义的makeCustomerHappy的特征保持一致:
public void processCustomer(int id, Consumer<Customer> makeCustomerHappy){ 
 Customer c = Database.getCustomerWithId(id); 
 makeCustomerHappy.accept(c); 
}

//现在,你可以很方便地通过传递Lambda表达式,直接插入不同的行为,不再需要继承OnlineBanking类了:
new OnlineBankingLambda().processCustomer(1337, (Customer c) -> 
 	System.out.println("Hello " + c.getName());

3.观察者模式

观察者模式是一种比较常见的方案,某些事件发生时(比如状态转变),如果一个对象(通常我们称之为主题)需要自动地通知其他多个对象(称为观察者),就会采用该方案。
使用 Lambda 重构面向对象的设计模式_第1张图片

//你需要为Twitter这样的应用设计并实现一个定制化的通知系统。想法很简单:好几家报纸机构,比如《纽约时报》《卫报》以及《世界报》都订阅了新闻
//他们希望当接收的新闻中包含他们感兴趣的关键字时,能得到特别通知。

```java
//首先,你需要一个观察者接口,它将不同的观察者聚合在一起。它仅有一个名为notify的方法,一旦接收到一条新的新闻,该方法就会被调用:
interface Observer { 
 void notify(String tweet); 
} 

//现在,你可以声明不同的观察者(比如,这里是三家不同的报纸机构),依据新闻中不同的
//关键字分别定义不同的行为:
class NYTimes implements Observer{ 
	 public void notify(String tweet) { 
		 if(tweet != null && tweet.contains("money")){ 
		 	System.out.println("Breaking news in NY! " + tweet); 
		 } 
	 } 
} 
class Guardian implements Observer{ 
	 public void notify(String tweet) { 
		 if(tweet != null && tweet.contains("queen")){ 
		 	System.out.println("Yet another news in London... " + tweet); 
		 } 
	 } 
} 
class LeMonde implements Observer{ 
	 public void notify(String tweet) { 
		 if(tweet != null && tweet.contains("wine")){ 
		 	System.out.println("Today cheese, wine and news! " + tweet); 
		 } 
	 } 
}

//你还遗漏了最重要的部分:Subject!让我们为它定义一个接口:
interface Subject{ 
 void registerObserver(Observer o); 
 void notifyObservers(String tweet); 
}


//Subject使用registerObserver方法可以注册一个新的观察者,使用notifyObservers方法通知它的观察者一个新闻的到来。让我们更进一步,实现Feed类:
class Feed implements Subject{ 
	 private final List<Observer> observers = new ArrayList<>(); 
	 public void registerObserver(Observer o) { 
	 	this.observers.add(o); 
	 } 
	 public void notifyObservers(String tweet) { 
	 	observers.forEach(o -> o.notify(tweet)); 
	 } 
}

//这是一个非常直观的实现:Feed类在内部维护了一个观察者列表,一条新闻到达时,它就进行通知。
Feed f = new Feed(); 
f.registerObserver(new NYTimes()); 
f.registerObserver(new Guardian()); 
f.registerObserver(new LeMonde()); 
f.notifyObservers("The queen said her favourite book is Java 8 in Action!");

//毫不意外,《卫报》会特别关注这条新闻!

//使用Lambda表达式
//你可能会疑惑Lambda表达式在观察者设计模式中如何发挥它的作用。
//不知道你有没有注意到,Observer接口的所有实现类都提供了一个方法:notify。
f.registerObserver((String tweet) -> { 
	 if(tweet != null && tweet.contains("money")){ 
	 	System.out.println("Breaking news in NY! " + tweet); 
	 } 
}); 
f.registerObserver((String tweet) -> { 
	 if(tweet != null && tweet.contains("queen")){ 
	 	System.out.println("Yet another news in London... " + tweet); 
	 } 
});

4. 责任链模式

责任链模式是一种创建处理对象序列(比如操作序列)的通用方案。一个处理对象可能需要在完成一些工作之后,将结果传递给另一个对象,这个对象接着做一些工作,再转交给下一个处理对象,以此类推。

public abstract class ProcessingObject<T> { 
 protected ProcessingObject<T> successor; 
 public void setSuccessor(ProcessingObject<T> successor){ 
 	this.successor = successor; 
 } 
 
 public T handle(T input){ 
	 T r = handleWork(input); 
	 if(successor != null){ 
	 	return successor.handle(r); 
	 } 
	 return r; 
 } 
 
 abstract protected T handleWork(T input); 
}

使用 Lambda 重构面向对象的设计模式_第2张图片

//下面让我们看看如何使用该设计模式。你可以创建两个处理对象,它们的功能是进行一些文本处理工作。
public class HeaderTextProcessing extends ProcessingObject<String> { 
   public String handleWork(String text){ 
   	  return "From Raoul, Mario and Alan: " + text; 
   } 
} 
public class SpellCheckerProcessing extends ProcessingObject<String> { 
   public String handleWork(String text){ 
   	  return text.replaceAll("labda", "lambda"); 
   } 
} 

//现在你就可以将这两个处理对象结合起来,构造一个操作序列!
ProcessingObject<String> p1 = new HeaderTextProcessing(); 
ProcessingObject<String> p2 = new SpellCheckerProcessing(); 
p1.setSuccessor(p2);

String result = p1.handle("Aren't labdas really sexy?!!"); 
System.out.println(result);

//使用Lambda表达式
UnaryOperator<String> headerProcessing = (String text) -> "From Raoul, Mario and Alan: " + text;
UnaryOperator<String> spellCheckerProcessing = (String text) -> text.replaceAll("labda", "lambda"); 

Function<String, String> pipeline =  headerProcessing.andThen(spellCheckerProcessing); 
String result = pipeline.apply("Aren't labdas really sexy?!!")

5.工厂模式

使用工厂模式,你无需向客户暴露实例化的逻辑就能完成对象的创建。

//比如,我们假定你为一家银行工作,他们需要一种方式创建不同的金融产品:贷款、期权、股票,等等。
//通常,你会创建一个工厂类,它包含一个负责实现不同对象的方法,如下所示:
public class ProductFactory { 
 	public static Product createProduct(String name){ 
		 switch(name){ 
			 case "loan": return new Loan(); 
			 case "stock": return new Stock(); 
			 case "bond": return new Bond(); 
			 default: throw new RuntimeException("No such product " + name); 
		 } 
   } 
}
//创建贷款(Loan)金融产品
Product p = ProductFactory.createProduct("loan");

//使用Lambda表达式
final static Map<String, Supplier<Product>> map = new HashMap<>(); 
static { 
 map.put("loan", Loan::new); 
 map.put("stock", Stock::new); 
 map.put("bond", Bond::new); 
}

//现在,你可以像之前使用工厂设计模式那样,利用这个Map来实例化不同的产品。
public static Product createProduct(String name){ 
    Supplier<Product> p = map.get(name); 
    if(p != null) return p.get(); 
    throw new IllegalArgumentException("No such product " + name); 
}

你可能感兴趣的:(#,java8)