当前位置: 首页 > article >正文

设计模式学习(四)

行为模式

观察者模式(Observer Pattern)

定义

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

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

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

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

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

  1. 定义状态接口
interface State {
    void turnOn();
    void turnOff();
}
  1. 定义具体状态类
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("电灯已经是关着的,无需操作");
    }
}
  1. 定义上下文类
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. 使用状态模式
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. 定义策略接口
interface PaymentStrategy {
    void pay(int amount);
}
  1. 定义具体策略类
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);
    }
}
  1. 定义上下文类
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. 使用策略模式
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 来执行排序。
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 根据设置的拒绝策略来处理无法执行的任务。
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 来执行不同的布局逻辑。
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 来计算动画的进度。
Animation animation = new AlphaAnimation(0, 1);
animation.setDuration(1000);

// 设置插值器策略
animation.setInterpolator(new AccelerateInterpolator());

模板方法模式(Template Method Design Pattern)

定义

它定义了一个算法的框架,并允许子类在不改变算法结构的情况下重新定义算法的某些步骤。模板方法模式通过将算法的通用部分放在父类中,而将可变部分留给子类来实现,从而实现了代码的复用和扩展。

模板方法的角色
  • AbstractClass(抽象类):定义算法的框架,并包含一个或多个抽象方法,这些方法由子类实现。
  • ConcreteClass(具体类):实现抽象类中的抽象方法,完成算法中特定步骤的具体实现。
例子

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

  1. 定义抽象类
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. 定义具体类
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("添加柠檬");
    }
}
  1. 使用模板方法模式
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):一个包含元素集合的类,它提供了一个方法,可以让访问者访问每一个元素。
例子
// 定义访问者接口
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);
    }
}

http://www.kler.cn/a/540340.html

相关文章:

  • [前端]CRX持久化
  • iOS AES/CBC/CTR加解密以及AES-CMAC
  • DeepSeek 实践总结
  • STM32G474--Whetstone程序移植(单精度)笔记
  • UMLS初探
  • HAL库外设宝典:基于CubeMX的STM32开发手册(持续更新)
  • 腾讯通RTX国产化升级迁移指南,兼容银行麒麟、统信等系统
  • WPS如何接入DeepSeek(通过第三方工具)
  • 【shellbash进阶系列】(一)SHELL脚本--简介
  • C#、.Net 中级高级架构管理面试题杂烩
  • 【详细版】DETR网络学习笔记(2020 ECCV)
  • C++模板编程——typelist的实现
  • 算法-动态规划-0-1背包问题(二维0-1背包,背包求方案数,求背包具体方案)
  • ollama下载很慢,如何换源,如何加速下载?
  • 网络编程 day3
  • Orange 开源项目介绍
  • Mp4视频播放机无法播放视频-批量修改视频分辨率(帧宽、帧高)
  • Docker 一文学会快速搭建ollama环境及运行deepseek-r1
  • bat命令 启动java jar 和停止 jar
  • 指定路径安装Ollama
  • WebRtc07: 音视频录制实战
  • 人岗匹配为核,打造精确高效招聘 “高速路”
  • 多模态识别和自然语言处理有什么区别
  • Tomcat添加到Windows系统服务中,服务名称带空格
  • 81页精品PPT | 华为流程与信息化实践与架构规划分享
  • 多头自注意力中的多头作用及相关思考