装饰器模式
概念:
它允许在不改变对象自身的情况下,动态地给对象添加额外的功能。通过使用装饰器模式,可以在运行时对对象进行扩展,而不需要创建大量的子类
应用:
当你希望在不修改原有类的情况下,给对象添加新的行为或状态时
当你需要在运行时组合多个功能,而不是在编译时就决定好时
当你有很多类需要组合不同的功能时,使用装饰器可以避免创建大量的子类
代码:
// 抽象组件
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());
}
}
适配器模式
概念:
用于解决两个不兼容接口之间的兼容性问题。它通过创建一个适配器类,将一个类的接口转换为另一个类期望的接口,从而使原本因接口不匹配而无法一起工作的类可以协同工作,主要有下面两种实现方式:
-
类适配器:通过继承目标类和适配者类,实现接口的适配。
-
对象适配器:通过组合的方式,将适配者类的对象作为成员变量,实现接口的适配。
应用:
系统扩展:当需要将第三方库或遗留代码集成到当前系统中,但接口不兼容时。
接口适配:当需要将一个类的接口转换为另一个类期望的接口时。
框架整合:当需要将不同框架或模块的接口进行整合时。
代码:
// 目标接口
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)维护一个观察者列表,当主题状态发生变化时,它会通知所有观察者对象,观察者对象则根据主题的状态变化更新自己的状态。
观察者模式通常涉及以下角色:
-
Subject(主题/被观察者):维护一个观察者列表,并提供注册和移除观察者的方法。当主题状态发生变化时,通知所有观察者。
-
Observer(观察者):定义了一个更新接口,用于接收主题的通知。
-
ConcreteSubject(具体主题):实现主题接口,维护主题的状态,并在状态变化时通知观察者。
-
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();
}
}