行为模式
观察者模式(Observer Pattern)
定义
它定义了对象之间的一对多依赖关系。当一个对象(被观察者)的状态发生变化时,所有依赖它的对象(观察者)都会收到通知并自动更新。
观察者模式的角色
- 被观察者(Subject):维护一个观察者列表,提供注册、删除和通知观察者的方法。
- 观察者(Observer):定义一个更新接口,用于接收被观察者的通知。
- 具体被观察者(ConcreteSubject):实现被观察者的具体逻辑,存储状态并通知观察者。
- 具体观察者(ConcreteObserver):实现观察者的更新接口,定义收到通知后的行为。
我们有一个新闻发布系统,新闻机构(被观察者)发布新闻时,订阅者(观察者)会收到通知并更新自己的状态。
- 定义观察者接口
java">interface Observer {void update(String news); // 更新方法
}
- 定义具体观察者
java">class Subscriber implements Observer {private String name;public Subscriber(String name) {this.name = name;}@Overridepublic void update(String news) {System.out.println(name + " 收到新闻: " + news);}
}
- 定义被观察者接口
java">interface Subject {void registerObserver(Observer observer); // 注册观察者void removeObserver(Observer observer); // 删除观察者void notifyObservers(String news); // 通知观察者
}
- 定义具体被观察者
java">class NewsAgency implements Subject {private List<Observer> observers = new ArrayList<>();private String news;@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers(String news) {for (Observer observer : observers) {observer.update(news);}}// 发布新闻public void setNews(String news) {this.news = news;notifyObservers(news);}
}
java">public class ObserverPatternDemo {public static void main(String[] args) {// 创建被观察者(新闻机构)NewsAgency newsAgency = new NewsAgency();// 创建观察者(订阅者)Observer subscriber1 = new Subscriber("Alice");Observer subscriber2 = new Subscriber("Bob");// 注册观察者newsAgency.registerObserver(subscriber1);newsAgency.registerObserver(subscriber2);// 发布新闻newsAgency.setNews("Breaking News: Java 17 Released!");// 移除一个观察者newsAgency.removeObserver(subscriber2);// 再次发布新闻newsAgency.setNews("Update: Java 17 Features Explained!");}
}
优点:
- 解耦被观察者和观察者,符合开闭原则。
- 支持动态添加和删除观察者。
- 实现了一对多的依赖关系,便于扩展。
缺点:
- 如果观察者过多,通知所有观察者可能会导致性能问题。
- 观察者和被观察者之间的依赖关系可能导致复杂的调用链。
jdk或者android系统上的应用
Java 提供了 java.util.Observable 类和 java.util.Observer 接口,可以直接使用它们实现观察者模式。
java">import java.util.Observable;
import java.util.Observer;// 被观察者
class NewsAgency extends Observable {private String news;public void setNews(String news) {this.news = news;setChanged(); // 标记状态已改变notifyObservers(news); // 通知观察者}
}// 观察者
class Subscriber implements Observer {private String name;public Subscriber(String name) {this.name = name;}@Overridepublic void update(Observable o, Object arg) {System.out.println(name + " 收到新闻: " + arg);}
}// 客户端代码
public class JavaObserverExample {public static void main(String[] args) {NewsAgency newsAgency = new NewsAgency();Subscriber subscriber1 = new Subscriber("Alice");Subscriber subscriber2 = new Subscriber("Bob");newsAgency.addObserver(subscriber1);newsAgency.addObserver(subscriber2);newsAgency.setNews("Breaking News: Java 17 Released!");}
}
状态设计模式(State Design Pattern)
定义
它允许对象在其内部状态改变时改变其行为。状态模式将对象的行为封装在不同的状态类中,使得对象在不同状态下有不同的行为表现,而不需要在代码中使用大量的条件语句。
状态模式的角色
- Context(上下文):定义客户端感兴趣的接口,并维护一个具体状态类的实例,这个实例定义了当前的状态。
- State(状态):定义一个接口,用于封装与Context的一个特定状态相关的行为。
- ConcreteState(具体状态):实现State接口,每个具体状态类实现一个与Context的状态相关的行为。
我们有一个电灯,它有两个状态:开和关。我们可以使用状态模式来实现这个电灯的行为。
- 定义状态接口
java">interface State {void turnOn();void turnOff();
}
- 定义具体状态类
java">class OnState implements State {@Overridepublic void turnOn() {System.out.println("电灯已经是开着的,无需操作");}@Overridepublic void turnOff() {System.out.println("电灯已关闭");}
}class OffState implements State {@Overridepublic void turnOn() {System.out.println("电灯已打开");}@Overridepublic void turnOff() {System.out.println("电灯已经是关着的,无需操作");}
}
- 定义上下文类
java">class LightSwitch {private State currentState;public LightSwitch() {// 初始状态为关闭currentState = new OffState();}public void setState(State state) {this.currentState = state;}public void turnOn() {currentState.turnOn();if (currentState instanceof OffState) {setState(new OnState());}}public void turnOff() {currentState.turnOff();if (currentState instanceof OnState) {setState(new OffState());}}
}
- 使用状态模式
java">public class StatePatternDemo {public static void main(String[] args) {LightSwitch lightSwitch = new LightSwitch();lightSwitch.turnOn(); // 电灯已打开lightSwitch.turnOn(); // 电灯已经是开着的,无需操作lightSwitch.turnOff(); // 电灯已关闭lightSwitch.turnOff(); // 电灯已经是关着的,无需操作}
}
策略设计模式(Strategy Design Pattern)
定义
它允许在运行时选择算法的行为。策略模式定义了一系列算法,并将每个算法封装起来,使它们可以互换。策略模式使得算法可以独立于使用它的客户端而变化。
策略模式的角色
- Context(上下文):维护一个对策略对象的引用,并提供一个接口来执行策略。
- Strategy(策略):定义一个公共接口,所有具体策略类都实现这个接口。
- ConcreteStrategy(具体策略):实现Strategy接口,提供具体的算法实现。
例子
有一个购物车系统,用户可以选择不同的支付方式(如信用卡支付、支付宝支付、微信支付等)。我们可以使用策略模式来实现不同的支付方式。
- 定义策略接口
java">interface PaymentStrategy {void pay(int amount);
}
- 定义具体策略类
java">class CreditCardPayment implements PaymentStrategy {private String cardNumber;private String name;public CreditCardPayment(String cardNumber, String name) {this.cardNumber = cardNumber;this.name = name;}@Overridepublic void pay(int amount) {System.out.println(amount + "元通过信用卡支付,卡号:" + cardNumber + ",持卡人:" + name);}
}class AlipayPayment implements PaymentStrategy {private String account;public AlipayPayment(String account) {this.account = account;}@Overridepublic void pay(int amount) {System.out.println(amount + "元通过支付宝支付,账户:" + account);}
}class WechatPayment implements PaymentStrategy {private String account;public WechatPayment(String account) {this.account = account;}@Overridepublic void pay(int amount) {System.out.println(amount + "元通过微信支付,账户:" + account);}
}
- 定义上下文类
java">class ShoppingCart {private PaymentStrategy paymentStrategy;public void setPaymentStrategy(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}public void checkout(int amount) {if (paymentStrategy == null) {System.out.println("请选择支付方式");return;}paymentStrategy.pay(amount);}
}
- 使用策略模式
java">public class StrategyPatternDemo {public static void main(String[] args) {ShoppingCart cart = new ShoppingCart();// 选择信用卡支付cart.setPaymentStrategy(new CreditCardPayment("1234-5678-9012-3456", "张三"));cart.checkout(1000);// 选择支付宝支付cart.setPaymentStrategy(new AlipayPayment("zhangsan@alipay.com"));cart.checkout(500);// 选择微信支付cart.setPaymentStrategy(new WechatPayment("zhangsan@wechat.com"));cart.checkout(300);}
}
jdk或者android系统上的应用
- java.util.Comparator
Comparator 接口是策略模式的经典应用。它允许在运行时定义不同的排序策略。
- 策略接口:Comparator 定义了 compare() 方法。
- 具体策略:可以实现不同的 Comparator 来定义不同的排序规则。
- 上下文:Collections.sort() 或 Arrays.sort() 方法使用 Comparator 来执行排序。
java">List<String> list = Arrays.asList("Banana", "Apple", "Cherry");// 策略1:按字母顺序排序
Collections.sort(list, (s1, s2) -> s1.compareTo(s2));
System.out.println(list); // [Apple, Banana, Cherry]// 策略2:按字符串长度排序
Collections.sort(list, (s1, s2) -> s1.length() - s2.length());
System.out.println(list); // [Apple, Cherry, Banana]
- java.util.concurrent.ThreadPoolExecutor
ThreadPoolExecutor 中的 RejectedExecutionHandler也是使用策略模式 。当线程池无法处理新任务时,可以通过设置不同的拒绝策略来处理。
- 策略接口:RejectedExecutionHandler 定义了 rejectedExecution() 方法。
- 具体策略:AbortPolicy、CallerRunsPolicy、DiscardPolicy、DiscardOldestPolicy 等实现了不同的拒绝策略。
- 上下文:ThreadPoolExecutor 根据设置的拒绝策略来处理无法执行的任务。
java">ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(2)
);// 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
- LayoutManager
在 Android 的 RecyclerView 中,LayoutManager 是一个典型的策略模式应用。RecyclerView 可以通过设置不同的 LayoutManager 来改变其布局行为。
- 策略接口:LayoutManager 定义了布局相关的接口。
- 具体策略:LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager 等实现了不同的布局策略。
- 上下文:RecyclerView 根据设置的 LayoutManager 来执行不同的布局逻辑。
java">RecyclerView recyclerView = findViewById(R.id.recyclerView);// 策略1:线性布局
recyclerView.setLayoutManager(new LinearLayoutManager(this));// 策略2:网格布局
recyclerView.setLayoutManager(new GridLayoutManager(this, 2));// 策略3:瀑布流布局
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
- Animation 插值器
在 Android 的动画系统中,Interpolator 是策略模式的应用。Interpolator 定义了动画的变化速率,可以通过设置不同的插值器来实现不同的动画效果。
- 策略接口:Interpolator 定义了 getInterpolation() 方法。
- 具体策略:LinearInterpolator、AccelerateInterpolator、DecelerateInterpolator 等实现了不同的插值逻辑。
- 上下文:Animation 根据设置的 Interpolator 来计算动画的进度。
java">Animation animation = new AlphaAnimation(0, 1);
animation.setDuration(1000);// 设置插值器策略
animation.setInterpolator(new AccelerateInterpolator());
模板方法模式(Template Method Design Pattern)
定义
它定义了一个算法的框架,并允许子类在不改变算法结构的情况下重新定义算法的某些步骤。模板方法模式通过将算法的通用部分放在父类中,而将可变部分留给子类来实现,从而实现了代码的复用和扩展。
模板方法的角色
- AbstractClass(抽象类):定义算法的框架,并包含一个或多个抽象方法,这些方法由子类实现。
- ConcreteClass(具体类):实现抽象类中的抽象方法,完成算法中特定步骤的具体实现。
例子
一个制作饮料的过程,包含烧水、冲泡、倒入杯子、添加调料。其中,烧水和倒入杯子是通用的步骤,而冲泡和添加调料是具体的步骤,因饮料类型不同而不同。我们可以使用模板方法模式来实现这个过程。
- 定义抽象类
java">abstract class Beverage {// 模板方法,定义了制作饮料的算法框架public final void prepareBeverage() {boilWater();brew();pourInCup();addCondiments();}// 通用步骤private void boilWater() {System.out.println("烧水");}private void pourInCup() {System.out.println("倒入杯子");}// 抽象方法,由子类实现protected abstract void brew();protected abstract void addCondiments();
}
- 定义具体类
java">class Coffee extends Beverage {@Overrideprotected void brew() {System.out.println("冲泡咖啡");}@Overrideprotected void addCondiments() {System.out.println("添加糖和牛奶");}
}class Tea extends Beverage {@Overrideprotected void brew() {System.out.println("冲泡茶叶");}@Overrideprotected void addCondiments() {System.out.println("添加柠檬");}
}
- 使用模板方法模式
java">public class TemplateMethodPatternDemo {public static void main(String[] args) {Beverage coffee = new Coffee();coffee.prepareBeverage();System.out.println("-------------------");Beverage tea = new Tea();tea.prepareBeverage();}
}
jdk或者android系统上的应用
- AbstractList
- AbstractList是JDK中List接口的一个抽象实现,它提供了一些List操作的默认实现。
- 在AbstractList中,addAll()等方法定义了操作的算法骨架,而一些具体的操作(如元素的添加)则留给子类去实现。
- ArrayList等具体子类继承了AbstractList,并提供了这些具体操作的具体实现。
- Handler类
- 在Android中,Handler类用于处理消息和Runnable对象。
- Handler类定义了一个处理消息的流程,即模板方法,但具体的消息处理逻辑则由继承自Handler的子类通过重写handleMessage(Message msg)方法来实现。
- Android框架为开发者提供了灵活的消息处理机制,开发者只需关注具体的消息处理逻辑,而无需关心消息处理的流程。
访问者模式(Visitor Pattern)
定义
它允许在不修改现有类结构的情况下,向现有类添加新的操作。访问者模式通过定义一个访问者接口,将算法与对象结构分离,从而实现扩展功能的目的。
访问者的角色
- 访问者(Visitor):访问者定义了一个访问具体元素的操作,它的每个方法对应一个具体元素类。
- 具体访问者(Concrete Visitor):实现访问者接口,完成对具体元素的操作。
- 元素(Element):定义一个接受访问者的操作,通常是一个接口或抽象类。
- 具体元素(Concrete Element):实现了元素接口或抽象类的类,它实现了接受访问的方法。
- 对象结构(Object Structure):一个包含元素集合的类,它提供了一个方法,可以让访问者访问每一个元素。
例子
java">// 定义访问者接口
interface Visitor {void visit(ConcreteElementA elementA);void visit(ConcreteElementB elementB);
}// 具体访问者,实现了对元素A和元素B的访问操作
class ConcreteVisitor implements Visitor {@Overridepublic void visit(ConcreteElementA elementA) {System.out.println("Visiting ConcreteElementA: " + elementA.getData());}@Overridepublic void visit(ConcreteElementB elementB) {System.out.println("Visiting ConcreteElementB: " + elementB.getData());}
}// 定义元素接口
interface Element {void accept(Visitor visitor);
}// 具体元素A,实现了元素接口
class ConcreteElementA implements Element {private String data;public ConcreteElementA(String data) {this.data = data;}public String getData() {return data;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 具体元素B,实现了元素接口
class ConcreteElementB implements Element {private String data;public ConcreteElementB(String data) {this.data = data;}public String getData() {return data;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 定义对象结构,包含元素集合
class ObjectStructure {private List<Element> elements = new ArrayList<>();public void addElement(Element element) {elements.add(element);}public void accept(Visitor visitor) {for (Element element : elements) {element.accept(visitor);}}
}// 测试类
public class VisitorPatternDemo {public static void main(String[] args) {ObjectStructure os = new ObjectStructure();os.addElement(new ConcreteElementA("Element A Data"));os.addElement(new ConcreteElementB("Element B Data"));Visitor visitor = new ConcreteVisitor();os.accept(visitor);}
}