Java设计模式

发布于:2024-12-08 ⋅ 阅读:(127) ⋅ 点赞:(0)

一、观察者设计模式

1.1 概述

观察者模式(Observer Pattern),又称发布-订阅模式,是一种行为设计模式。它定义了一种一对多的依赖关系,允许多个观察者对象同时监听某个主题对象(Subject)。当主题对象的状态发生变化时,它会通知所有注册的观察者,以便这些观察者能够自动更新自身的状态。

1.2 结构

观察者模式通常包含以下角色:

  1. Subject(主题)
    • 抽象主题角色,负责维护观察者的列表。
    • 提供接口以添加和删除观察者。
    • 通常包括方法如 attach(observer)detach(observer)
  2. ConcreteSubject(具体主题)
    • 实现了 Subject 接口的具体类,维护有关状态。
    • 当状态变化时,调用通知方法以更新所有观察者。
  3. Observer(观察者)
    • 抽象观察者角色,定义更新接口,通常是 update() 方法。
    • 观察者在收到主题变化的通知时调用该方法更新自身状态。
  4. ConcreteObserver(具体观察者)
    • 实现 Observer 接口的具体类。
    • 在更新方法中实现如何响应主题变化。

例子:
在使用微信公众号时,大家都会有这样的体验,当你关注的公众号中有新内容更新的话,它就会推送给关注公众号的微信用户端。我们使用观察者模式来模拟这样的场景

  • 微信用户就是观察者
  • 微信公众号是被观察者
    有多个的微信用户关注了这个公众号。
    在这里插入图片描述
// 观察者接口
public interface Observer {
    void update(String message); // 接收更新消息
}

// 主题接口
public interface Subject {
    void attach(Observer observer); // 添加观察者
    void detach(Observer observer); // 删除观察者
    void notifyObservers(String message); // 通知观察者更新消息
}

// 具体主题类
import java.util.ArrayList;
import java.util.List;

public class WeChatOfficialAccount implements Subject {
    private List<Observer> observers = new ArrayList<>(); // 观察者列表

    @Override
    public void attach(Observer observer) {
        observers.add(observer);
        System.out.println(observer + " 关注了公众号。");
    }

    @Override
    public void detach(Observer observer) {
        observers.remove(observer);
        System.out.println(observer + " 取消关注了公众号。");
    }

    @Override
    public void notifyObservers(String message) {
        System.out.println("公众号发布新内容: " + message);
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

// 具体观察者类
public class WeChatUser implements Observer {
    private String name;

    public WeChatUser(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " 收到了新推送: " + message);
    }

    @Override
    public String toString() {
        return name; // 方便打印
    }
}

// 示例用法
public class WeChatObserverPattern {
    public static void main(String[] args) {
        // 创建公众号
        WeChatOfficialAccount wechatAccount = new WeChatOfficialAccount();

        // 创建微信用户
        WeChatUser user1 = new WeChatUser("用户A");
        WeChatUser user2 = new WeChatUser("用户B");
        WeChatUser user3 = new WeChatUser("用户C");

        // 用户关注公众号
        wechatAccount.attach(user1);
        wechatAccount.attach(user2);
        wechatAccount.attach(user3);

        // 发布新内容
        wechatAccount.notifyObservers("今天的天气真不错!");

        // 用户取消关注
        wechatAccount.detach(user2);

        // 再次发布新内容
        wechatAccount.notifyObservers("明天有一场特别活动!");
    }
}

1.3 特点

1. 优点

  • 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
  • 被观察者发送通知,所有注册的观察者都会收到信息(可以实现广播机制)。

2. 缺点

  • 如果观察者非常多的话,那么所有的观察者收到被观察者发送的通知会耗时。
  • 如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调用,会导致系统崩溃。

3. 使用场景

  • 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。
  • 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面时。

1.4 JDK中的实现

在Java中,通过iava.util. Observable类和java.util. observer接口定义了观察者模式,只要实现它们的子类就可以编写 观察者模式实例。

1. Observable 类

Observable 类是抽象目标类(被观察者),它有一个 Vector 集合成员变量,用于保存所有要通知的观察者对象。它的三个重要方法如下:

  • void addObserver(Observer o)
    用于将新的观察者对象添加到集合中。

  • void notifyObservers(Object arg)
    调用集合中的所有观察者对象的 update 方法,通知它们数据发生改变。通常,越晚加入集合的观察者越先得到通知。

  • void setChanged()
    用来设置一个 boolean 类型的内部标志,注明目标对象发生了变化。当它为 true 时,notifyObservers() 才会通知观察者。

2. Observer 接口

Observer 接口是抽象观察者,它监视目标对象的变化。当目标对象发生变化时,观察者会得到通知,并调用 update 方法进行相应的工作。

3. 例子

import java.util.Observable;
import java.util.Observer;

// 具体的被观察者类
class WeatherData extends Observable {
    private float temperature;

    public void setTemperature(float temperature) {
        this.temperature = temperature;
        setChanged(); // 标记状态已更改
        notifyObservers(temperature); // 通知观察者
    }
}

// 具体的观察者类
class CurrentConditionsDisplay implements Observer {
    private float temperature;

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof WeatherData) {
            this.temperature = (float) arg; // 更新温度
            display(); // 显示当前条件
        }
    }

    public void display() {
        System.out.println("Current temperature: " + temperature + " degrees.");
    }
}

// 主程序
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();

        weatherData.addObserver(currentDisplay); // 注册观察者
        weatherData.setTemperature(25.5f); // 更新温度,触发通知
        weatherData.setTemperature(30.0f); // 再次更新温度
    }
}

二、模板设计模式

模板方法设计模式( Template Method Design Pattern ),在一个方法中定义一个算法骨架(即模板),并将某些步骤推迟到子类中实现
该模式在父类中定义一个方法的骨架(或算法的框架),并允许子类在不改变算法结构的情况下重新定义该算法的某些步骤。

举例:

  • 创建一个抽象类,定义算法骨架:
// 抽象类,定义制作饮料的模板方法
abstract class Beverage {

    // 模板方法,定义了制作饮料的通用步骤
    public final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        if (customerWantsCondiments()) { // 钩子方法,子类可以选择重写
            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();

    // 钩子方法:决定是否添加调料,子类可以选择重写
    protected boolean customerWantsCondiments() {
        return true; // 默认添加调料
    }
}
  • 创建具体的子类,实现抽象类中定义的抽象方法:
// 具体类:茶
class Tea extends Beverage {

    @Override
    protected void brew() {
        System.out.println("Steeping the tea");
    }

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

    // 重写钩子方法,茶默认不添加调料
    @Override
    protected boolean customerWantsCondiments() {
        return false;
    }
}
// 具体类:咖啡
class Coffee extends Beverage {

    @Override
    protected void brew() {
        System.out.println("Dripping coffee through filter");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding sugar and milk");
    }
}
  • 客户端代码:
// 客户端代码
public class TemplateMethodPatternExample {
    public static void main(String[] args) {
        System.out.println("Preparing tea:");
        Beverage tea = new Tea();
        tea.prepareRecipe();

        System.out.println("\nPreparing coffee:");
        Beverage coffee = new Coffee();
        coffee.prepareRecipe();
    }
}
  • 输出:
Preparing tea:
Boiling water
Steeping the tea
Pouring into cup

Preparing coffee:
Boiling water
Dripping coffee through filter
Pouring into cup
Adding sugar and milk
  • Beverage 抽象类定义了模板方法prepareRecipe,并封装了制作饮料的固定步骤
  • brew()addCondiments() 是由子类实现的抽象方法,各自实现了茶和咖啡的制作过程
  • 钩子方法 customerWantsCondiments()允许子类控制是否执行某个步骤

三、单例设计模式

单例模式有以下特点:

  1. 单例类只能有一个实例。
  2. 单例类必须自己创建自己的唯一实例。
  3. 单例类必须给所有其他对象提供这一实例。

一、懒汉式单例

在第一次访问时实例化自己

//懒汉式单例类.在第一次调用的时候实例化自己 
public class Singleton {
    private Singleton() {}
    private static Singleton single=null;
    //静态工厂方法 
    public static Singleton getInstance() {
         if (single == null) {  
             single = new Singleton();
         }  
        return single;
    }
}

Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。

如果走到single == null时发生线程切换,会存在线程不安全的问题。

有三种方式确保懒汉式单例的线程安全问题:

  1. 在getInstance上加上同步:
public static synchronized Singleton getInstance() {
         if (single == null) {  
             single = new Singleton();
         }  
        return single;
}
  1. 双重检查锁定
public static Singleton getInstance() {
        if (singleton == null) {  
            synchronized (Singleton.class) {  
               if (singleton == null) {  
                  singleton = new Singleton(); 
               }  
            }  
        }  
        return singleton; 
}
  1. 静态内部类
public class Singleton {  
    private static class LazyHolder {  
       private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
       return LazyHolder.INSTANCE;  
    }  
}  
  • 静态内部类的特点
    • LazyHolder 是一个静态内部类,它只有在第一次被访问时才会被加载和初始化。
    • 类加载是线程安全的,JVM 在加载类时会确保类加载的线程安全性。
  • INSTANCE 的初始化
    • LazyHolder 内的 INSTANCE 是一个 static final 的变量,它在 LazyHolder 被加载时完成初始化。
    • static final 保证了 INSTANCE 的初始化只会发生一次,并且由 JVM 保证线程安全。
  • 特点:延迟加载,线程安全,利用类加载机制实现,推荐使用。

第三种比1、2好,即实现了线程安全,又避免了同步带来的性能影响

二、饿汉式单例

饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

//饿汉式单例类.在类初始化时,已经自行实例化 
public class Singleton1 {
    private Singleton1() {}
    private static final Singleton1 single = new Singleton1();
    //静态工厂方法 
    public static Singleton1 getInstance() {
        return single;
    }
}
  • 特点:线程安全,类加载时初始化,简单实现,但可能会造成资源浪费。

四、Builder模式

4.1 概述

Builder 模式是一种创建型设计模式,通过逐步构建复杂对象,将对象的构建过程与表示分离,使得同样的构建过程可以创建不同的对象。

特点

  1. 将对象构建与其表示分离:
    • 构建复杂对象时,不直接实例化对象,而是使用 Builder 逐步设置属性,最后通过 build() 方法生成对象。
  2. 灵活性和可扩展性:
    • 新增属性或功能只需修改 Builder 类,而无需更改已有的构造代码。
  3. 链式调用:
    • Builder 模式允许链式设置属性,代码可读性更强。

4.2 结构

  1. 产品类(Product)
    • 要创建的复杂对象。
    • 包含多个属性,通常是不可变的。
  2. 构建器类(Builder)
    • 定义构建对象的步骤,每个步骤设置对象的一个属性。
    • 提供 build() 方法返回完整的产品对象。
  3. 具体构建器(ConcreteBuilder)
    • 实现构建器类,包含构建对象的具体逻辑。
  4. 指导者类(Director,可选)
    • 用于控制构建过程的顺序和逻辑。
    • 实际应用中常常省略,由客户端直接调用 Builder。

4.3 具体实现

比如我们现在要自定义一个http发送请求连接:

传统的方式(构造函数)

http对象代码为:

public class HttpRequest {
    private String url;
    private String method;
    private Map<String, String> headers;
    private String body;

    public HttpRequest(String url, String method, Map<String, String> headers, String body) {
        this.url = url;
        this.method = method;
        this.headers = headers != null ? headers : new HashMap<>();
        this.body = body;
    }

    @Override
    public String toString() {
        return "HttpRequest { " +
               "url='" + url + '\'' +
               ", method='" + method + '\'' +
               ", headers=" + headers +
               ", body='" + body + '\'' +
               " }";
    }
}

构建方式:

public class Main {
    public static void main(String[] args) {
        // 构建请求
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put("Authorization", "Bearer token123");

        HttpRequest request = new HttpRequest(
                "https://api.example.com/data", // URL
                "POST",                         // 方法
                headers,                        // Headers
                "{\"key\":\"value\"}"           // Body
        );

        System.out.println(request);
    }
}

问题分析

  • 构造器参数过多时,易混淆或出错,特别是可选参数场景。
  • 代码可读性差

传统方式(Set函数)
http对象代码:

public class HttpRequest {
    private String url;
    private String method;
    private Map<String, String> headers = new HashMap<>();
    private String body;

    public void setUrl(String url) {
        this.url = url;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public void setHeader(String key, String value) {
        this.headers.put(key, value);
    }

    public void setBody(String body) {
        this.body = body;
    }

    @Override
    public String toString() {
        return "HttpRequest { " +
               "url='" + url + '\'' +
               ", method='" + method + '\'' +
               ", headers=" + headers +
               ", body='" + body + '\'' +
               " }";
    }
}

构建方式:

public class Main {
    public static void main(String[] args) {
        // 构建请求
        HttpRequest request = new HttpRequest();
        request.setUrl("https://api.example.com/data");
        request.setMethod("POST");
        request.setHeader("Content-Type", "application/json");
        request.setHeader("Authorization", "Bearer token123");
        request.setBody("{\"key\":\"value\"}");

        System.out.println(request);
    }
}

问题分析

  • 缺点: 无法保证对象的完整性(可能遗漏某些关键参数),容易导致不一致的状态

为什么改用 Builder 模式

  • 参数过多且部分可选时,传统方式可读性差。
  • Builder 模式可以链式调用,代码更清晰。
  • Builder 可封装复杂的初始化逻辑,确保对象的一致性和不可变性。

改进后的builder:

  1. PRODUCT
public class HttpRequest {
    private String url;        // 必填
    private  String method;     // 必填
    private Map<String, String> headers; // 可选
    private String body;       // 可选

    // 私有构造器,确保只能通过 Builder 创建
    private HttpRequest(String url, String method, Map<String, String> headers, String body) {
        this.url = url;
        this.method = method;
        this.headers = headers;
        this.body = body;
    }

    // Getters
    public String getUrl() { return url; }
    public String getMethod() { return method; }
    public Map<String, String> getHeaders() { return headers; }
    public String getBody() { return body; }
}
  1. 构建器类(Builder)
public interface Builder {
    Builder setUrl(String url);
    Builder setMethod(String method);
    Builder addHeader(String key, String value);
    Builder setBody(String body);
    HttpRequest build();
}
  1. 具体构建器(ConcreteBuilder)
import java.util.HashMap;
import java.util.Map;

public class HttpRequestBuilder implements Builder {
    private String url;
    private String method;
    private Map<String, String> headers = new HashMap<>();
    private String body;

    @Override
    public Builder setUrl(String url) {
        this.url = url;
        return this;
    }

    @Override
    public Builder setMethod(String method) {
        this.method = method;
        return this;
    }

    @Override
    public Builder addHeader(String key, String value) {
        this.headers.put(key, value);
        return this;
    }

    @Override
    public Builder setBody(String body) {
        this.body = body;
        return this;
    }

    @Override
    public HttpRequest build() {
        // 校验必填参数
        if (url == null || method == null) {
            throw new IllegalStateException("URL and Method are required!");
        }
        return new HttpRequest(url, method, headers, body);
    }
}

  1. 指导者类(Director,可选)
public class HttpRequestDirector {
    private final Builder builder;

    public HttpRequestDirector(Builder builder) {
        this.builder = builder;
    }

    public HttpRequest constructGetRequest(String url) {
        return builder.setUrl(url)
                      .setMethod("GET")
                      .build();
    }

    public HttpRequest constructPostRequest(String url, String body) {
        return builder.setUrl(url)
                      .setMethod("POST")
                      .setBody(body)
                      .addHeader("Content-Type", "application/json")
                      .build();
    }
}
  1. 客户端代码
public class Main {
    public static void main(String[] args) {
        // 使用 Builder 直接构建
        HttpRequest request1 = new HttpRequestBuilder()
                .setUrl("https://api.example.com/resource")
                .setMethod("GET")
                .addHeader("Authorization", "Bearer token123")
                .build();

        System.out.println("Request1: " + request1.getUrl());

        // 使用 Director 构建
        HttpRequestDirector director = new HttpRequestDirector(new HttpRequestBuilder());
        HttpRequest request2 = director.constructPostRequest("https://api.example.com/resource", "{\"key\":\"value\"}");

        System.out.println("Request2: " + request2.getBody());
    }
}

Builder 的优势

  1. 强制性:
    • 必须设置关键参数(如 URL、method),否则无法创建对象。
  2. 校验性:
    • build() 方法集中校验,确保对象状态一致。
  3. 可读性:
    • 链式调用使代码更直观,避免参数顺序错误。

通过这种方式,Builder 模式能够显著提升代码的安全性和可靠性,避免遗漏关键参数的问题。

4.4 使用场景

  1. 参数多且部分可选的对象构建
    • 如配置类、网络请求对象(如 oKHttp)、数据库连接对象等。
  2. 不可变对象的构建
    • 需要在对象创建后禁止修改时,如 StringBuilderImmutable 对象。
  3. 复杂初始化逻辑的对象
    • 如需要组合多个子对象或处理复杂逻辑的初始化。
  4. 跨平台对象创建
    • 如需要动态生成 JSON、XML 等结构。
  5. 避免构造器参数过多
    • 如果构造器参数多且顺序容易搞混,Builder 模式可以显著改善代码可读性和安全性。

五、责任链设计模式

5.1 定义:

责任链模式是一种行为设计模式,它允许多个对象按顺序处理请求,而不明确指定处理者。请求沿着链传递,直到某个对象处理它或链的末端。

责任链也可以想象成推卸责任
假设要去公司领取资料,首先向公司前台打听要去哪里领取资料,她告诉我们去”营业窗口“。等到了”营业窗口“后,又被告知应该去”售后部门“。等我们好不容易赶到了”售后部门“,又被告知应该去”资料中心“,因此最后不得不去”资料中心“。

在找到合适的办事人之前,被不断踢给一个又一个人,这就是”推卸责任“。

这种模式,当外部请求程序进行某个处理,但程序暂时无法直接决定由哪个对象负载处理时,就需要推卸责任。这种情况下,可以考虑将多个对象组成一条责任链,然后按照它们在职责链上的顺序一个一个地找出到底应该谁来负责

5.2 结构:

  1. Handler(抽象处理者)
    • 定义处理请求的方法 handleRequest
    • 保存下一个处理者的引用。
  2. ConcreteHandler(具体处理者)
    • 实现具体的处理逻辑。
    • 如果当前处理者无法处理请求,则将请求传递给下一个处理者。
  3. Client(客户端)
    • 向第一个ConcreteHandler角色发送请求的角色,创建责任链并发送请求

5.3 举例

表单验证

  • 场景:用户提交表单时,需要对不同字段进行依次验证(如非空、格式、长度等)。
  • 实现:每个验证规则是责任链中的一个节点,如果当前验证失败,则返回错误;否则传递给下一个验证器。
  1. 定义一个抽象的处理类(Handler):

    abstract class Validator {
    	//定义下一个验证器,即推卸责任的对象
        protected Validator next;
    
        public void setNext(Validator next) {
            this.next = next;
        }
    
        public abstract boolean validate(String input);
    }
    
  2. 然后,我们创建具体的处理类(ConcreteHandler),它们继承自抽象的处理类,并实现了自己的处理逻辑validate:

    class NotEmptyValidator extends Validator {
        @Override
        public boolean validate(String input) {
            if (input == null || input.isEmpty()) {
                System.out.println("Field cannot be empty");
                return false;
            }
            return next == null || next.validate(input);
        }
    }
    
    class LengthValidator extends Validator {
        @Override
        public boolean validate(String input) {
            if (input.length() > 10) {
                System.out.println("Input too long");
                return false;
            }
            return next == null || next.validate(input);
        }
    }
    
  3. 最后,在客户端代码中创建处理器对象,并将它们连接起来:

    // 客户端代码
    Validator validator = new NotEmptyValidator();
    validator.setNext(new LengthValidator());
    validator.validate("TestInput");
    

5.4 应用场景

  • 多个对象可以处理一个请求,但具体由哪个对象处理该请求在运行时自动确定。
  • 可动态指定一组对象处理请求,或添加新的处理者。
  • 需要在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。

六、策略模式

问题描述:

  • 有各种鸭子(北京鸭、玩具鸭),鸭子有各种行为(叫、飞)
  • 希望能够实现不同的鸭子,显示不同鸭子的信息

传统方法会创建一个抽象类

    public abstract class Duck{
        public Duck(){
            
        }
        
        public abstract  void display();//显示鸭子信息
        
        public void fly(){
            System.out.println("鸭子会飞翔");
        }
    }

这时候我们要实现具体的鸭子,如玩具鸭,得重写Duck类里的所有方法,因为玩具鸭不会飞。如果要实现北京鸭,又得重写Duck类里的所有方法,因为北京鸭飞飞行能力一般。

传统方式存在问题:

  • 其他鸭子都继承了Duck类,所有fly让所有的子类都会飞了,这是不正确的
  • 即继承带来的问题:对类的局部改动,尤其超类的局部改动,会影响其他部分,会有溢出效应

这时引出策略模式

  • 策略模式中,定义算法族(策略组),分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户

我的理解是:
把原来继承的部分换成一个插槽,这个插槽在策略模式中是一个接口。不同的类插槽处的具体实现不一样,这时候我们可以搭建很多个不一样的积木(策略组),用哪一个就把哪一个积木放到插槽里,不用对插槽进行重新改动,这样后面的其他人也可以重复使用这个积木。策略模式中具体的实现是:积木即继承了接口的实现类,使用哪一个实现了就将其赋值给接口即可,不用重新接口方法。

实例:
策略模式的原则就是,分离变化部分,封装接口,基于接口编程各种功能

将原来的方法定义改成策略接口(创建一个插槽)

public abstract class Duck{
    
    //属性,策略接口
    FlyBehavior flyBehavior;

    public abstract  void display();//显示鸭子信息

    public void fly(){
        //改进
        if(flyBehavior!=null){
            flyBehavior.fly();
        }
    }
    
    //提供给用户,动态变化行为动作(更换插槽里的积木调用这个方法就行)
    public  void setFlyBehavior(FlyBehavior flyBehavior){
        this.flyBehavior = flyBehavior;
    }
}

策略接口:

public interface FlyBehavior {
    void fly();//子类的具体实现
}

策略组的实现(实现放到接口里的积木):

public class GoodFlyBehavior implements FlyBehavior{
    @Override
    public void fly() {
        System.out.println("飞翔技术高超");
    }
}
public class NoFlyFlyBehavior implements FlyBehavior{
    @Override
    public void fly() {
        System.out.println("不会飞翔");
    }
}

不同鸭子的实现:

public class ToyDuck extends Duck{

    @Override
    public void display() {
    	//把想放的积木放到插槽里
        flyBehavior = new NoFlyFlyBehavior();
    }
}
public class BeiJingDuck extends Duck{

    @Override
    public void display() {
        flyBehavior = new GoodFlyBehavior();
    }
}

即将项目中变化的部分分离出来,多用组合/聚合,少用继承;用行为类组合,而不是行为的继承。

体现了“对修改关闭,对扩展开放”原则,客户端增加行为不用修改原有代码,只需要添加一种策略即可。

需要注意的是:没添加一个策略就需要增加一个类,当策略过多是会导致类数目庞大。

实例
通过定义一组算法接口(如存储操作),让不同的存储服务(OSS、MinIO)实现具体的逻辑,客户端只需依赖接口,动态选择实现即可。

// 1. 策略接口
public interface StorageStrategy {
    void upload(String file);
}

// 2. 具体策略:OSS
public class OSSStorage implements StorageStrategy {
    @Override
    public void upload(String file) {
        System.out.println("Uploading to OSS: " + file);
    }
}

// 3. 具体策略:MinIO
public class MinIOStorage implements StorageStrategy {
    @Override
    public void upload(String file) {
        System.out.println("Uploading to MinIO: " + file);
    }
}
// 4. 上下文类
public class StorageContext {
    private StorageStrategy strategy;

    public StorageContext(StorageStrategy strategy) {
        this.strategy = strategy;
    }

    public void setStrategy(StorageStrategy strategy) {
        this.strategy = strategy;
    }

    public void uploadFile(String file) {
        strategy.upload(file);
    }
}
// 5. 客户端使用
public class Main {
    public static void main(String[] args) {
        StorageContext context = new StorageContext(new OSSStorage());
        context.uploadFile("file1.txt"); // 使用 OSS 上传

        context.setStrategy(new MinIOStorage());
        context.uploadFile("file2.txt"); // 使用 MinIO 上传
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到