设计模式学习(四)

ops/2025/2/8 21:46:37/

行为模式

观察者模式(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/ops/156812.html

相关文章

使用PHPStudy搭建Cloudreve网盘服务

文章目录 1、前言2、本地网站搭建 2.1 环境使用2.2 支持组件选择2.3 网页安装2.4 测试和使用2.5 问题解决 3、本地网页发布 3.1 cpolar云端设置3.2 cpolar本地设置 4、公网访问测试5、结语 1、前言 自云存储概念兴起已经有段时间了&#xff0c;各互联网大厂也纷纷加入战局&…

超详细UE4(虚幻4)第一人称射击(FPS)游戏制作教程

超详细UE4(虚幻4)第一人称射击(FPS)游戏制作教程 引言 在游戏开发领域,第一人称射击(FPS)游戏一直是最受欢迎的类型之一。从经典的《反恐精英》(CS)到现代的《使命召唤》(Call of Duty),FPS游戏凭借其紧张刺激的游戏体验和高度沉浸感,吸引了无数玩家。如果你是一…

SQL带外注入

SQL 带外注入&#xff08;Out-of-Band SQL Injection, OOB SQLi&#xff09; 是 SQL 注入的一种特殊类型&#xff0c;主要用于以下情况&#xff1a; 数据库没有直接返回错误信息&#xff08;比如被防火墙拦截了&#xff09;。无法使用常规注入手法&#xff08;如 UNION、错误信…

git:恢复纯版本库

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

Linux:基础IO(二.缓冲区、模拟一下缓冲区、详细讲解文件系统)

目录 1. 缓冲区 1.1 概念 1.2 作用与意义 2. 语言级别的缓冲区 2.1 刷新策略 2.2 具体在哪里 2.3 支持格式化 3. 自己来模拟一下缓冲区 3.1 项目文件规划 3.2 mystandard.h 3.3 mystandard.c 3.4 main.c 4.文件系统 4.1磁盘机械结构 4.2磁盘的物理存储 4.3磁盘的…

分享2款 .NET 开源且强大的翻译工具

前言 对于程序员而言永远都无法逃避和英文打交道&#xff0c;今天大姚给大家分享2款 .NET 开源、功能强大的翻译工具&#xff0c;希望可以帮助到有需要的同学。 STranslate STranslate是一款由WPF开源的、免费的&#xff08;MIT License&#xff09;、即开即用、即用即走的翻…

【自动化测试】使用Python selenium类库模拟手人工操作网页

使用Python selenium类库模拟手人工操作网页 背景准备工作安装Python版本安装selenium类库下载selenium驱动配置本地环境变量 自动化脚本输出页面表单自动化填充相关代码 背景 待操作网页必须使用IE浏览器登录访问用户本地只有edge浏览器&#xff0c;通过edge浏览器IE模式访问…

【spring】参数校验Validation

前言 在实际开发中&#xff0c;我们无法保证客户端传来的请求都是合法的。比如一些要求必传的参数没有传递&#xff0c;传来的参数长度不符合要求等&#xff0c;这种时候如果放任不管&#xff0c;继续执行后续业务逻辑&#xff0c;很有可能就会出现意想不到的bug。 有人可能会…