设计模式学习(四)
行为模式
观察者模式(Observer Pattern)
定义
它定义了对象之间的一对多依赖关系。当一个对象(被观察者)的状态发生变化时,所有依赖它的对象(观察者)都会收到通知并自动更新。
观察者模式的角色
- 被观察者(Subject):维护一个观察者列表,提供注册、删除和通知观察者的方法。
- 观察者(Observer):定义一个更新接口,用于接收被观察者的通知。
- 具体被观察者(ConcreteSubject):实现被观察者的具体逻辑,存储状态并通知观察者。
- 具体观察者(ConcreteObserver):实现观察者的更新接口,定义收到通知后的行为。
我们有一个新闻发布系统,新闻机构(被观察者)发布新闻时,订阅者(观察者)会收到通知并更新自己的状态。
- 定义观察者接口
interface Observer {
void update(String news); // 更新方法
}
- 定义具体观察者
class Subscriber implements Observer {
private String name;
public Subscriber(String name) {
this.name = name;
}
@Override
public void update(String news) {
System.out.println(name + " 收到新闻: " + news);
}
}
- 定义被观察者接口
interface Subject {
void registerObserver(Observer observer); // 注册观察者
void removeObserver(Observer observer); // 删除观察者
void notifyObservers(String news); // 通知观察者
}
- 定义具体被观察者
class NewsAgency implements Subject {
private List<Observer> observers = new ArrayList<>();
private String news;
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String news) {
for (Observer observer : observers) {
observer.update(news);
}
}
// 发布新闻
public void setNews(String news) {
this.news = news;
notifyObservers(news);
}
}
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 接口,可以直接使用它们实现观察者模式。
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;
}
@Override
public 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的状态相关的行为。
我们有一个电灯,它有两个状态:开和关。我们可以使用状态模式来实现这个电灯的行为。
- 定义状态接口
interface State {
void turnOn();
void turnOff();
}
- 定义具体状态类
class OnState implements State {
@Override
public void turnOn() {
System.out.println("电灯已经是开着的,无需操作");
}
@Override
public void turnOff() {
System.out.println("电灯已关闭");
}
}
class OffState implements State {
@Override
public void turnOn() {
System.out.println("电灯已打开");
}
@Override
public void turnOff() {
System.out.println("电灯已经是关着的,无需操作");
}
}
- 定义上下文类
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());
}
}
}
- 使用状态模式
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接口,提供具体的算法实现。
例子
有一个购物车系统,用户可以选择不同的支付方式(如信用卡支付、支付宝支付、微信支付等)。我们可以使用策略模式来实现不同的支付方式。
- 定义策略接口
interface PaymentStrategy {
void pay(int amount);
}
- 定义具体策略类
class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
private String name;
public CreditCardPayment(String cardNumber, String name) {
this.cardNumber = cardNumber;
this.name = name;
}
@Override
public void pay(int amount) {
System.out.println(amount + "元通过信用卡支付,卡号:" + cardNumber + ",持卡人:" + name);
}
}
class AlipayPayment implements PaymentStrategy {
private String account;
public AlipayPayment(String account) {
this.account = account;
}
@Override
public void pay(int amount) {
System.out.println(amount + "元通过支付宝支付,账户:" + account);
}
}
class WechatPayment implements PaymentStrategy {
private String account;
public WechatPayment(String account) {
this.account = account;
}
@Override
public void pay(int amount) {
System.out.println(amount + "元通过微信支付,账户:" + account);
}
}
- 定义上下文类
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);
}
}
- 使用策略模式
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 来执行排序。
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 根据设置的拒绝策略来处理无法执行的任务。
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 来执行不同的布局逻辑。
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 来计算动画的进度。
Animation animation = new AlphaAnimation(0, 1);
animation.setDuration(1000);
// 设置插值器策略
animation.setInterpolator(new AccelerateInterpolator());
模板方法模式(Template Method Design Pattern)
定义
它定义了一个算法的框架,并允许子类在不改变算法结构的情况下重新定义算法的某些步骤。模板方法模式通过将算法的通用部分放在父类中,而将可变部分留给子类来实现,从而实现了代码的复用和扩展。
模板方法的角色
- AbstractClass(抽象类):定义算法的框架,并包含一个或多个抽象方法,这些方法由子类实现。
- ConcreteClass(具体类):实现抽象类中的抽象方法,完成算法中特定步骤的具体实现。
例子
一个制作饮料的过程,包含烧水、冲泡、倒入杯子、添加调料。其中,烧水和倒入杯子是通用的步骤,而冲泡和添加调料是具体的步骤,因饮料类型不同而不同。我们可以使用模板方法模式来实现这个过程。
- 定义抽象类
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();
}
- 定义具体类
class Coffee extends Beverage {
@Override
protected void brew() {
System.out.println("冲泡咖啡");
}
@Override
protected void addCondiments() {
System.out.println("添加糖和牛奶");
}
}
class Tea extends Beverage {
@Override
protected void brew() {
System.out.println("冲泡茶叶");
}
@Override
protected void addCondiments() {
System.out.println("添加柠檬");
}
}
- 使用模板方法模式
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):一个包含元素集合的类,它提供了一个方法,可以让访问者访问每一个元素。
例子
// 定义访问者接口
interface Visitor {
void visit(ConcreteElementA elementA);
void visit(ConcreteElementB elementB);
}
// 具体访问者,实现了对元素A和元素B的访问操作
class ConcreteVisitor implements Visitor {
@Override
public void visit(ConcreteElementA elementA) {
System.out.println("Visiting ConcreteElementA: " + elementA.getData());
}
@Override
public 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;
}
@Override
public 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;
}
@Override
public 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);
}
}