设计模式学习(四)

devtools/2025/2/11 18:00:28/

行为模式

观察者模式(Observer Pattern)

定义

它定义了对象之间的一对多依赖关系。当一个对象(被观察者)的状态发生变化时,所有依赖它的对象(观察者)都会收到通知并自动更新。

观察者模式的角色
  • 被观察者(Subject):维护一个观察者列表,提供注册、删除和通知观察者的方法。
  • 观察者(Observer):定义一个更新接口,用于接收被观察者的通知。
  • 具体被观察者(ConcreteSubject):实现被观察者的具体逻辑,存储状态并通知观察者。
  • 具体观察者(ConcreteObserver):实现观察者的更新接口,定义收到通知后的行为。

我们有一个新闻发布系统,新闻机构(被观察者)发布新闻时,订阅者(观察者)会收到通知并更新自己的状态。

  1. 定义观察者接口
java">interface Observer {void update(String news);  // 更新方法
}
  1. 定义具体观察者
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);}
}
  1. 定义被观察者接口
java">interface Subject {void registerObserver(Observer observer);  // 注册观察者void removeObserver(Observer observer);    // 删除观察者void notifyObservers(String news);         // 通知观察者
}
  1. 定义具体被观察者
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的状态相关的行为。

我们有一个电灯,它有两个状态:开和关。我们可以使用状态模式来实现这个电灯的行为。

  1. 定义状态接口
java">interface State {void turnOn();void turnOff();
}
  1. 定义具体状态类
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("电灯已经是关着的,无需操作");}
}
  1. 定义上下文类
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());}}
}
  1. 使用状态模式
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接口,提供具体的算法实现。
例子

有一个购物车系统,用户可以选择不同的支付方式(如信用卡支付、支付宝支付、微信支付等)。我们可以使用策略模式来实现不同的支付方式。

  1. 定义策略接口
java">interface PaymentStrategy {void pay(int amount);
}
  1. 定义具体策略类
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);}
}
  1. 定义上下文类
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);}
}
  1. 使用策略模式
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系统上的应用
  1. 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]
  1. 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());
  1. 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));
  1. 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(具体类):实现抽象类中的抽象方法,完成算法中特定步骤的具体实现。
例子

一个制作饮料的过程,包含烧水、冲泡、倒入杯子、添加调料。其中,烧水和倒入杯子是通用的步骤,而冲泡和添加调料是具体的步骤,因饮料类型不同而不同。我们可以使用模板方法模式来实现这个过程。

  1. 定义抽象类
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();
}
  1. 定义具体类
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("添加柠檬");}
}
  1. 使用模板方法模式
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系统上的应用
  1. AbstractList
  • AbstractList是JDK中List接口的一个抽象实现,它提供了一些List操作的默认实现。
  • 在AbstractList中,addAll()等方法定义了操作的算法骨架,而一些具体的操作(如元素的添加)则留给子类去实现。
  • ArrayList等具体子类继承了AbstractList,并提供了这些具体操作的具体实现。
  1. 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);}
}

http://www.ppmy.cn/devtools/157992.html

相关文章

网络工程师 (29)CSMA/CD协议

前言 CSMA/CD协议&#xff0c;即载波监听多路访问/碰撞检测&#xff08;Carrier Sense Multiple Access with Collision Detection&#xff09;协议&#xff0c;是一种在计算机网络中&#xff0c;特别是在以太网环境下&#xff0c;用于管理多个设备共享同一物理传输介质的重要…

【AI学习】关于 DeepSeek-R1的几个流程图

遇见关于DeepSeek-R1的几个流程图&#xff0c;清晰易懂形象直观&#xff0c;记录于此。 流程图一 来自文章《Understanding Reasoning LLMs》&#xff0c; 文章链接&#xff1a;https://magazine.sebastianraschka.com/p/understanding-reasoning-llms?continueFlagaf07b1a0…

国内知名Deepseek培训师培训讲师唐兴通老师讲授AI人工智能大模型实践应用

课程名称 《Deepseek人工智能大模型实践应用》 课程目标 全面了解Deepseek人工智能大模型的技术原理、功能特点及应用场景。 熟练掌握Deepseek大模型的提示词工程技巧&#xff0c;能够编写高质量的提示词。 掌握Deepseek大模型在办公、营销等领域的应用方法&#xff0c;提升…

2024美团春招硬件开发笔试真题及答案解析

目录 一、选择题 1、在 Linux,有一个名为 file 的文件,内容如下所示: 2、在 Linux 中,关于虚拟内存相关的说法正确的是() 3、AT89S52单片机中,在外部中断响应的期间,中断请求标志位查询占用了()。 4、下列关于8051单片机的结构与功能,说法不正确的是()? 5、…

C++字符串相关内容

字符串 字符串&#xff0c;本质上是一个接一个字符的一组字符。字母、数字、符号等。 const char* 字符串名 字符后面会有一个空终止符&#xff0c;为0。 字符串从指针的内存地址开始&#xff0c;然后继续下去&#xff0c;直到它碰到0&#xff0c;然后意识到字符串终止了。 …

SpringCloud面试题----Nacos和Eureka的区别

功能特性 服务发现 Nacos&#xff1a;支持基于 DNS 和 RPC 的服务发现&#xff0c;提供了更为灵活的服务发现机制&#xff0c;能满足不同场景下的服务发现需求。Eureka&#xff1a;主要基于 HTTP 的 RESTful 接口进行服务发现&#xff0c;客户端通过向 Eureka Server 发送 HT…

ASP.NET Core程序的部署

发布 不能直接把bin/Debug部署到生产环境的服务器上&#xff0c;性能低。应该创建网站的发布版&#xff0c;用【发布】功能。两种部署模式&#xff1a;“框架依赖”和“独立”。独立模式选择目标操作系统和CPU类型。Windows、Linux、iOS&#xff1b;关于龙芯。 网站的运行 在…

[LeetCode] day19 454. 四数相加 II

题目链接 题目描述 给你四个整数数组 nums1、nums2、nums3 和 nums4 &#xff0c;数组长度都是 n &#xff0c;请你计算有多少个元组 (i, j, k, l) 能满足&#xff1a; 0 < i, j, k, l < n nums1[i] nums2[j] nums3[k] nums4[l] 0 示例 1&#xff1a; 输入&…