【Android】行为型设计模式—策略模式、模版方法模式、观察者模式

策略模式

策略模式是一种行为设计模式,它定义了一系列算法,并将每一个算法封装起来,让它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。
uses > Context +contextInterface() Strategy +algorithm() ConcreteStrategyA +algorithm() ConcreteStrategyB +algorithm()

  • Context:上下文角色,用来操作策略的上下文环境,起到承上启下的作用,屏蔽高层模块对策略、算法的直接访问。
  • Stragety:抽象策略角色,策略、算法的抽象,通常为接口。
  • ConcreteStragety:具体的策略实现。

简单实现

策略模式的简单实现通常涉及以下几个部分:定义一个策略接口,然后根据不同的算法实现该接口,最后在一个上下文类中使用这些策略。以下是一个简化的示例:

(1)策略接口

策略接口定义了一个方法,所有的具体策略类都需要实现这个方法。

java 复制代码
public interface Strategy {
    int execute(int a, int b);
}

(2)具体策略类

我们实现不同的策略类来执行不同的算法。比如,加法减法乘法

java 复制代码
// 加法策略
public class AddStrategy implements Strategy {
    @Override
    public int execute(int a, int b) {
        return a + b;
    }
}

// 减法策略
public class SubtractStrategy implements Strategy {
    @Override
    public int execute(int a, int b) {
        return a - b;
    }
}

// 乘法策略
public class MultiplyStrategy implements Strategy {
    @Override
    public int execute(int a, int b) {
        return a * b;
    }
}

(3)上下文类

上下文类 Context 使用策略接口来调用具体的策略类。

java 复制代码
public class Context {
    private Strategy strategy;

    // 设置策略
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    // 执行策略
    public int executeStrategy(int a, int b) {
        return strategy.execute(a, b);
    }
}

(4)测试类

在测试类中,我们可以通过设置不同的策略来运行不同的算法。

java 复制代码
public class StrategyPatternExample {
    public static void main(String[] args) {
        Context context = new Context();

        // 使用加法策略
        context.setStrategy(new AddStrategy());
        System.out.println("10 + 5 = " + context.executeStrategy(10, 5));

        // 使用减法策略
        context.setStrategy(new SubtractStrategy());
        System.out.println("10 - 5 = " + context.executeStrategy(10, 5));

        // 使用乘法策略
        context.setStrategy(new MultiplyStrategy());
        System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
    }
}

(5)输出

text 复制代码
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50

使用场景和优缺点

  • 使用场景:

    • 对客户隐藏具体策略(算法)的实现细节,彼此完全独立
    • 针对同一类型问题的多种处理方式,仅具体行为有差别时
    • 在一个类中定义了很多行为,而且这些行为在这个类里的操作以多个条件语句的形式出现。策略模式将相关的条件分支移入它们各自的Strategy类中,以代替这些条件语句
  • 优点:

    • 使用策略模式可以避免使用多重条件语句。多重条件语句不易维护,而且易出错
    • 易于拓展。当需要添加一个策略时,只需要实现接口就可以了
  • 缺点:

    • 每一个策略都是一个类,复用性小。如果策略过多,类的数量会增多
    • 上层模块必须知道有哪些策略,才能够使用这些策略,这与迪米特原则相违背

模版方法模式

模版方法模式是一种行为设计模式,它定义了一个操作中的算法骨架,并允许子类在不改变算法结构的情况下,重新定义算法的某些步骤。该模式通过继承实现,父类负责封装大致流程,而具体细节则由子类提供。
AbstractClass -stepOne() -stepTwo() -stepThree() +execute() ConcreteClassA ConcreteClassB

  • 抽象类(AbstractClass):定义了算法的模板方法和一些基本方法。模板方法一般是一个封装了算法骨架的固定方法,它不允许子类修改,只有算法的个别步骤可以由子类重写。
  • 具体类(ConcreteClass):实现抽象类中的某些方法,具体实现各个步骤的细节。

简单实现

假设我们有一个抽象的制作咖啡和茶的流程。虽然制作的步骤相似(比如加热水、倒水等),但是具体的饮料制作细节有所不同(如茶需要浸泡,而咖啡需要过滤)。

(1)抽象类

java 复制代码
public abstract class Beverage {
    // 模版方法,定义了制作饮料的骨架
    public final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    // 固定步骤:烧水
    private void boilWater() {
        System.out.println("Boiling water");
    }

    // 固定步骤:倒入杯中
    private void pourInCup() {
        System.out.println("Pouring into cup");
    }

    // 变动步骤:由子类实现
    protected abstract void brew();  // 不同饮料的冲泡方式不同

    // 变动步骤:由子类实现
    protected abstract void addCondiments();  // 不同饮料的调料不同
}

(2)具体类:咖啡

java 复制代码
public class Coffee extends Beverage {
    @Override
    protected void brew() {
        System.out.println("Brewing coffee");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding sugar and milk");
    }
}

(3)具体类:茶

java 复制代码
public class Tea extends Beverage {
    @Override
    protected void brew() {
        System.out.println("Steeping the tea");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding lemon");
    }
}

(4)客户端代码

java 复制代码
public class TemplateMethodExample {
    public static void main(String[] args) {
        Beverage coffee = new Coffee();
        Beverage tea = new Tea();

        System.out.println("Making coffee:");
        coffee.prepareRecipe();  // 按照模板做咖啡

        System.out.println("\nMaking tea:");
        tea.prepareRecipe();  // 按照模板做茶
    }
}

(5)输出

text 复制代码
Making coffee:
Boiling water
Brewing coffee
Pouring into cup
Adding sugar and milk

Making tea:
Boiling water
Steeping the tea
Pouring into cup
Adding lemon

使用场景和优缺点

  • 使用场景:

    • 多个子类有共有的方法,并且逻辑基本相同时

    • 面对重要、复杂的算法,可以把核心算法设计为模板方法,周边相关细节功能则由各个子类实现。

    • 需要通过子类来决定父类算法中的某个步骤是否执行,实现子类对父类的反向控制。

  • 优点:

    • 模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。子类实现算法的某
    • 些细节,有助于算法的扩展。
  • 缺点:

    • 每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象

观察者模式

观察者模式是一种行为设计模式,用于定义对象之间的一对多依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都会自动得到通知并更新。这个模式通常用于事件驱动的系统中。
+subject 1 * Subject +attach(o: Observer) +detach(o: Observer) +notify() Observer +update() ConcreteSubject ConcreteObserver

  • Subject:抽象主题(抽象被观察者)。抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加或删除观察者对象。
  • ConcreteSubiect:具体主题(具体被观察者)。该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
  • Observer:抽象观察者,是观察者的抽象类。它定义了一个更新接口,使得在得到主题更改通知时更新自己。
  • ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态

简单实现

假设有一个天气预报系统,天气变化时,多个设备(如温度显示、气象站等)需要接收到天气变化的通知。

(1)主题(被观察者)接口

java 复制代码
public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

(2)观察者接口

java 复制代码
public interface Observer {
    void update(float temperature, float humidity, float pressure);
}

(3)具体主题(天气数据)

java 复制代码
public class WeatherData implements Subject {
    private List<Observer> observers;
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {
        observers = new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature, humidity, pressure);
        }
    }

    // 更新天气数据
    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        notifyObservers(); // 数据更新后通知所有观察者
    }
}

(4)具体观察者(温度显示)

java 复制代码
public class TemperatureDisplay implements Observer {
    private float temperature;

    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        display();
    }

    public void display() {
        System.out.println("Temperature Display: " + temperature + "°C");
    }
}

(5)具体观察者(气象站)

java 复制代码
public class WeatherStation implements Observer {
    private float temperature;
    private float humidity;
    private float pressure;

    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        display();
    }

    public void display() {
        System.out.println("Weather Station - Temperature: " + temperature + "°C, Humidity: " + humidity + "%, Pressure: " + pressure + "hPa");
    }
}

(6)客户端代码(测试)

java 复制代码
public class ObserverPatternExample {
    public static void main(String[] args) {
        // 创建主题对象
        WeatherData weatherData = new WeatherData();

        // 创建观察者对象
        TemperatureDisplay tempDisplay = new TemperatureDisplay();
        WeatherStation weatherStation = new WeatherStation();

        // 注册观察者
        weatherData.registerObserver(tempDisplay);
        weatherData.registerObserver(weatherStation);

        // 更新天气数据并通知所有观察者
        weatherData.setMeasurements(25.5f, 65.0f, 1013.1f);
        weatherData.setMeasurements(27.0f, 60.0f, 1012.5f);
    }
}

(7)输出

text 复制代码
Temperature Display: 25.5°C
Weather Station - Temperature: 25.5°C, Humidity: 65.0%, Pressure: 1013.1hPa
Temperature Display: 27.0°C
Weather Station - Temperature: 27.0°C, Humidity: 60.0%, Pressure: 1012.5hPa

使用场景和优缺点

  • 使用场景:
    • 关联行为场景。需要注意的是,关联行为是可拆分的,而不是"组合"关系
    • 事件多级触发场景
    • 跨系统的消息交换场景,如消息队列、事件总线的处理机制。
  • 优点:
    • 观察者和被观察者之间是抽象耦合的,容易扩展。
    • 方便建立一套触发机制。
  • 缺点:在应用观察者模式时需要考虑一下开发效率和运行效率的问题。程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂;而且在Java中消息的通知一般是顺序执行的,那么一个观察者卡顿,会影响整体的执行效率。在这种情况下,一般会采用异步方式。

已经到底啦!!

相关推荐
小王子10241 分钟前
设计模式Python版 组合模式
python·设计模式·组合模式
linwq82 小时前
设计模式学习(二)
java·学习·设计模式
恋猫de小郭3 小时前
Android Studio 正式版 10 周年回顾,承载 Androider 的峥嵘十年
android·ide·android studio
aaaweiaaaaaa6 小时前
php的使用及 phpstorm环境部署
android·web安全·网络安全·php·storm
工程师老罗8 小时前
Android记事本App设计开发项目实战教程2025最新版Android Studio
android
pengyu12 小时前
系统化掌握 Dart 编程之异常处理(二):从防御到艺术的进阶之路
android·flutter·dart
消失的旧时光-194312 小时前
android Camera 的进化
android
基哥的奋斗历程13 小时前
Openfga 授权模型搭建
android·adb
Pakho love1 天前
Linux:文件与fd(被打开的文件)
android·linux·c语言·c++
小王子10241 天前
设计模式Python版 桥接模式
python·设计模式·桥接模式