设计模式-(装饰器,适配器,观察者,外观)

news/2025/2/26 18:51:21

装饰器模式

概念:

它允许在不改变对象自身的情况下,动态地给对象添加额外的功能。通过使用装饰器模式,可以在运行时对对象进行扩展,而不需要创建大量的子类

应用:

当你希望在不修改原有类的情况下,给对象添加新的行为或状态时

当你需要在运行时组合多个功能,而不是在编译时就决定好时

当你有很多类需要组合不同的功能时,使用装饰器可以避免创建大量的子类

代码:
// 抽象组件
abstract class Beverage {
    String description = "Unknown Beverage";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

// 具体组件
class Coffee extends Beverage {
    public Coffee() {
        description = "Coffee";
    }

    public double cost() {
        return 2.00;
    }
}

// 装饰器抽象类
abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();
}

// 具体装饰器
class Milk extends CondimentDecorator {
    Beverage beverage;

    public Milk(Beverage beverage) {
        this.beverage = beverage;
    }

    public String getDescription() {
        return beverage.getDescription() + ", Milk";
    }

    public double cost() {
        return 0.50 + beverage.cost();
    }
}

class Sugar extends CondimentDecorator {
    Beverage beverage;

    public Sugar(Beverage beverage) {
        this.beverage = beverage;
    }

    public String getDescription() {
        return beverage.getDescription() + ", Sugar";
    }

    public double cost() {
        return 0.25 + beverage.cost();
    }
}

// 测试装饰器模式
public class CoffeeShop {
    public static void main(String[] args) {
        Beverage beverage = new Coffee();
        System.out.println(beverage.getDescription() + " $" + beverage.cost());

        beverage = new Milk(beverage);
        System.out.println(beverage.getDescription() + " $" + beverage.cost());

        beverage = new Sugar(beverage);
        System.out.println(beverage.getDescription() + " $" + beverage.cost());
    }
}

适配器模式

概念:

用于解决两个不兼容接口之间的兼容性问题。它通过创建一个适配器类,将一个类的接口转换为另一个类期望的接口,从而使原本因接口不匹配而无法一起工作的类可以协同工作,主要有下面两种实现方式:

  1. 类适配器:通过继承目标类和适配者类,实现接口的适配。

  2. 对象适配器:通过组合的方式,将适配者类的对象作为成员变量,实现接口的适配。

应用:

系统扩展:当需要将第三方库或遗留代码集成到当前系统中,但接口不兼容时。

接口适配:当需要将一个类的接口转换为另一个类期望的接口时。

框架整合:当需要将不同框架或模块的接口进行整合时。

代码:
// 目标接口
interface MediaPlayer {
    void play(String audioType, String fileName);
}

// 需要适配的接口1
class VlcPlayer {
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: " + fileName);
    }
}

// 需要适配的接口2
class Mp4Player {
    public void playMp4(String fileName) {
        System.out.println("Playing mp4 file. Name: " + fileName);
    }
}

// 适配器类(对象适配器)
class MediaAdapter implements MediaPlayer {
    private VlcPlayer vlcPlayer;
    private Mp4Player mp4Player;

    public MediaAdapter(String audioType) {
        if (audioType.equalsIgnoreCase("vlc")) {
            vlcPlayer = new VlcPlayer();
        } else if (audioType.equalsIgnoreCase("mp4")) {
            mp4Player = new Mp4Player();
        }
    }

    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            vlcPlayer.playVlc(fileName);
        } else if (audioType.equalsIgnoreCase("mp4")) {
            mp4Player.playMp4(fileName);
        }
    }
}

// 客户端代码
class AudioPlayer implements MediaPlayer {
    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("mp3")) {
            System.out.println("Playing mp3 file. Name: " + fileName);
        } else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
            MediaAdapter mediaAdapter = new MediaAdapter(audioType);
            mediaAdapter.play(audioType, fileName);
        } else {
            System.out.println("Invalid media. " + audioType + " format not supported");
        }
    }
}

// 测试代码
public class AdapterPatternDemo {
    public static void main(String[] args) {
        AudioPlayer audioPlayer = new AudioPlayer();

        // 播放MP3文件
        audioPlayer.play("mp3", "beyond the horizon.mp3");

        // 播放VLC文件
        audioPlayer.play("vlc", "youve got to hide your love away.vlc");

        // 播放MP4文件
        audioPlayer.play("mp4", "mind me.mp4");
    }
}

观察者模式

概念:

观察者模式的核心思想是“一对多”的依赖关系。主题(Subject)维护一个观察者列表,当主题状态发生变化时,它会通知所有观察者对象,观察者对象则根据主题的状态变化更新自己的状态。

观察者模式通常涉及以下角色:

  1. Subject(主题/被观察者):维护一个观察者列表,并提供注册和移除观察者的方法。当主题状态发生变化时,通知所有观察者。

  2. Observer(观察者):定义了一个更新接口,用于接收主题的通知。

  3. ConcreteSubject(具体主题):实现主题接口,维护主题的状态,并在状态变化时通知观察者。

  4. ConcreteObserver(具体观察者):实现观察者接口,根据主题的状态变化更新自己的状态。

应用:

事件驱动系统:当一个事件发生时,需要通知多个订阅者。

用户界面交互:例如,当用户输入数据时,需要更新多个相关的界面组件。

消息发布/订阅系统:当消息发布者发布消息时,所有订阅者都会收到通知。

数据绑定:当数据源发生变化时,所有绑定到该数据源的视图都会自动更新

代码:
// 观察者接口
interface Observer {
    void update(float temperature, float humidity, float pressure);
}

// 主题接口
interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}

// 具体主题类
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 o) {
        observers.add(o);
    }

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

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

    // 模拟天气数据变化
    public void measurementsChanged() {
        notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
}

// 具体观察者类1
class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;
    private Subject weatherData;

    public CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

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

    public void display() {
        System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
    }
}

// 具体观察者类2
class StatisticsDisplay implements Observer {
    private float maxTemp = 0.0f;
    private float minTemp = 200;
    private float tempSum = 0.0f;
    private int numReadings;
    private Subject weatherData;

    public StatisticsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

    @Override
    public void update(float temperature, float humidity, float pressure) {
        tempSum += temperature;
        numReadings++;
        if (temperature > maxTemp) {
            maxTemp = temperature;
        }
        if (temperature < minTemp) {
            minTemp = temperature;
        }
        display();
    }

    public void display() {
        System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings) + "/" + maxTemp + "/" + minTemp);
    }
}

// 测试代码
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();

        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);

        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
        weatherData.setMeasurements(78, 90, 29.2f);
    }
}

外观模式

概念:

提供一个统一的高层接口,将复杂的子系统封装起来,使得客户端可以更简单地与子系统交互。它隐藏了子系统的复杂性,仅暴露一个简化的接口给客户端

应用:

简化复杂子系统的接口:当一个系统由多个子系统组成,且这些子系统的接口复杂时,外观模式可以提供一个简化的接口。

分层架构中的层间交互:在分层架构中,外观模式可以作为每层的入口点,简化层与层之间的依赖关系。

模块整合:在大型系统中,外观模式可以封装多个模块的复杂交互,为外部提供统一的接口。

封装第三方库:当使用复杂的第三方库时,外观模式可以封装其复杂接口,提供更简单的使用方式

代码:
public class TV {
    public void turnOn() {
        System.out.println("电视已打开");
    }

    public void turnOff() {
        System.out.println("电视已关闭");
    }
}

public class AirConditioner {
    public void turnOn() {
        System.out.println("空调已打开");
    }

    public void turnOff() {
        System.out.println("空调已关闭");
    }
}

public class Window {
    public void open() {
        System.out.println("窗户已打开");
    }

    public void close() {
        System.out.println("窗户已关闭");
    }
}
public class SmartHomeFacade {
    private TV tv;
    private AirConditioner airConditioner;
    private Window window;

    public SmartHomeFacade() {
        tv = new TV();
        airConditioner = new AirConditioner();
        window = new Window();
    }

    public void turnOnAll() {
        tv.turnOn();
        airConditioner.turnOn();
        window.open();
    }

    public void turnOffAll() {
        tv.turnOff();
        airConditioner.turnOff();
        window.close();
    }
}
public class Client {
    public static void main(String[] args) {
        SmartHomeFacade smartHome = new SmartHomeFacade();

        System.out.println("回家,开启家电");
        smartHome.turnOnAll();

        System.out.println("\n离家,关闭家电");
        smartHome.turnOffAll();
    }
}


http://www.niftyadmin.cn/n/5869075.html

相关文章

高中数学基础-统计和概率

文章目录 一、统计基础二、概率三、计数原理四、随机变量 高中数学基础-统计和概率 一、统计基础 总体、个体&#xff1a;所有元素称为总体&#xff0c;其中一个元素称为个体普查、抽查&#xff1a;所有元素都检查一遍称为普查&#xff0c;对部分样本进行抽取检查称为抽查&…

BUG: 解决新版本SpringBoot3.4.3在创建项目时勾选lombok但无法使用的问题

前言 当使用Spring Boot 3.4.3创建新项目时&#xff0c;即使正确勾选Lombok依赖&#xff0c;编译时仍出现找不到符号的错误&#xff0c;但代码中Lombok注解的使用完全正确。 原因 Spring Boot 3.4.3在自动生成的pom.xml中新增了maven-compiler-plugin的配置&#xff0c;该插件…

精美登录注册UI,登录页面设计模板

精美登录注册UI,登录页面设计模板 引言 在网页设计中,按钮是用户交互的重要元素之一。一个炫酷的按钮特效不仅能提升用户体验,还能为网页增添独特的视觉吸引力。今天,我们将通过CSS和JavaScript来实现一个“精美登录注册UI,登录页面设计模板”。该素材呈现了数据符号排版…

父组件用的是原生监听,子组件用的是onClick,子组件添加了stopPropagation还是没有阻止传播

父组件用事件监听&#xff0c;子组件用onClick&#xff0c;即使子组件加了stopPropagation还是没有阻止冒泡。父组件可能使用原生的addEventListener来绑定事件&#xff0c;而子组件用的是React的onClick事件。这时候&#xff0c;虽然子组件调用了e.stopPropagation()&#xff…

ubuntu-24.04.1-desktop 中的 QT6.7 QtCreator 调试程序

ubuntu-24.04.1-desktop 中的 QT6.7 QtCreator 中调试程序 &#xff11; 启动调试时提示&#xff1a;The kit does not have a debugger set.&#xff12; CDB配置问题&#xff12;.1 选择 工具 -> 外部 -> 配置&#xff12;.2 配置 CDB 路径 &#xff11; 启动调试时提示…

C++ | 面向对象 | 类

&#x1f47b;类 &#x1f47e;语法格式 class className{Access specifiers: // 访问权限DataType variable; // 变量returnType functions() { } // 方法 };&#x1f47e;访问权限 class className {public:// 公有成员protected:// 受保护成员private:// 私有成员 }…

Node.js包管理工具选型指南

Node.js包管理工具选型指南 一、核心工具矩阵对比 1.1 主流工具特性对比&#xff08;2025版&#xff09; 工具名称最新版本安装速度磁盘效率安全特性适用场景推荐指数引用来源npm10.5.0⭐⭐⭐⭐基础校验小型项目/兼容性要求高⭐⭐⭐14Yarn4.1.0⭐⭐⭐⭐⭐⭐⭐完整性校验审计企…

2022年全国职业院校技能大赛网络系统管理赛项模块A:网络构建(样题6)-网络部分解析-附详细代码

目录 附录1:拓扑图 附录2:地址规划表 1.SW1 2.SW2 3.SW3 4.SW4 5.VSU 6.SW7 7.R1 8.R2 9.R3 10.AC1 11.AC2 12.EG1 13.EG2 附录1:拓扑图 附录2:地址规划表