23种设计模式简单记录

23种设计模式主要分为三大类:创建型模式、结构型模式和行为型模式。下面是这些设计模式的概览:

创建型模式(Creational Patterns)

  1. 单例模式(Singleton):确保一个类只有一个实例,并提供一个全局访问点。
  2. 工厂方法模式(Factory Method):定义一个用于创建对象的接口,但让子类决定实例化哪一个类。
  3. 抽象工厂模式(Abstract Factory):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
  4. 建造者模式(Builder):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
  5. 原型模式(Prototype):用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。

结构型模式(Structural Patterns)

  1. 适配器模式(Adapter) :将一个类的接口转换成客户希望的另一个接口。

    1. MusicPlayerAdapter 类作为适配器,它实现了 PlayMusicV2 接口,并在内部持有一个 PlayMusicV1 对象的引用。当客户端调用 play 方法时,适配器会根据传入的参数调用旧接口的 playMp3 方法,从而实现了接口的转换,让旧的音频播放器库能够适应新的应用程序接口。例子:

      java 复制代码
      // 原有的接口
      interface PlayMusicV1 {
          void playMp3(String filename);
      }
      
      // 新的接口
      interface PlayMusicV2 {
          void play(String audioType, String filename);
      }
      
      // 第三方库的实现类
      class OldMusicPlayer implements PlayMusicV1 {
          @Override
          public void playMp3(String filename) {
              System.out.println("Playing MP3 file: " + filename);
          }
      }
      
      // 适配器类
      class MusicPlayerAdapter implements PlayMusicV2 {
          private final PlayMusicV1 player;
      
          public MusicPlayerAdapter(PlayMusicV1 player) {
              this.player = player;
          }
      
          @Override
          public void play(String audioType, String filename) {
              if ("mp3".equalsIgnoreCase(audioType)) {
                  player.playMp3(filename);
              } else {
                  System.out.println("Unsupported audio type: " + audioType);
              }
          }
      }
      
      // 客户端代码
      public class Client {
          public static void main(String[] args) {
              PlayMusicV1 oldPlayer = new OldMusicPlayer();
              PlayMusicV2 adapter = new MusicPlayerAdapter(oldPlayer);
              
              // 使用新接口播放MP3
              adapter.play("mp3", "favorite_song.mp3");
          }
      }
  2. 桥接模式(Bridge):将抽象部分与它的实现部分分离,使它们都可以独立地变化。

  3. 组合模式(Composite):允许你将对象组合成树形结构来表示整体/部分层次结构。

  4. 装饰器模式(Decorator):动态地给一个对象添加一些额外的职责。

  5. 外观模式(Facade):为子系统中的一组接口提供一个一致的界面,简化接口。

  6. 享元模式(Flyweight):运用共享技术有效支持大量细粒度的对象。

  7. 代理模式(Proxy) :为其他对象提供一种代理以控制对这个对象的访问。

    1. 代理模式通过提供一个代理对象来控制对真实对象的访问,这个代理对象可以在访问真实对象前进行一些预处理操作,或者在访问后进行一些后续处理。下面是一个简单的Java代理模式示例,我们以租房为例,说明静态代理和动态代理的实现。

      静态代理示例

      首先定义一个租房服务的接口:

      1public interface RentHouse {
      2    void rent();
      3}
      

      接着实现这个接口的真实对象(房东):

      1public class RealEstate implements RentHouse {
      2    @Override
      3    public void rent() {
      4        System.out.println("房东出租房子");
      5    }
      6}
      

      然后创建一个静态代理类,也实现相同的接口:

      1public class HouseAgency implements RentHouse {
      2    private RealEstate realEstate;
      3
      4    public HouseAgency(RealEstate realEstate) {
      5        this.realEstate = realEstate;
      6    }
      7
      8    @Override
      9    public void rent() {
      10        preProcess();
      11        realEstate.rent();
      12        postProcess();
      13    }
      14
      15    private void preProcess() {
      16        System.out.println("中介进行房源展示、咨询等前期工作");
      17    }
      18
      19    private void postProcess() {
      20        System.out.println("中介完成合同签订等后续工作");
      21    }
      22}
      

      最后是客户端代码,使用代理来租房:

      1public class Client {
      2    public static void main(String[] args) {
      3        RealEstate realEstate = new RealEstate();
      4        RentHouse proxy = new HouseAgency(realEstate);
      5        proxy.rent();
      6    }
      7}
      

      动态代理示例

      动态代理通常使用Java的java.lang.reflect.Proxy类来创建代理对象,这里使用JDK动态代理为例:

      首先,保持RentHouse接口和RealEstate类不变。

      动态代理类如下:

      1import java.lang.reflect.InvocationHandler;
      2import java.lang.reflect.Method;
      3import java.lang.reflect.Proxy;
      4
      5public class DynamicProxy implements InvocationHandler {
      6    private Object target;
      7
      8    public Object bind(Object target) {
      9        this.target = target;
      10        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
      11                target.getClass().getInterfaces(), this);
      12    }
      13
      14    @Override
      15    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      16        preProcess();
      17        Object result = method.invoke(target, args);
      18        postProcess();
      19        return result;
      20    }
      21
      22    private void preProcess() {
      23        System.out.println("动态代理:中介进行房源展示、咨询等前期工作");
      24    }
      25
      26    private void postProcess() {
      27        System.out.println("动态代理:中介完成合同签订等后续工作");
      28    }
      29}
      

      客户端代码调整为:

      1public class Client {
      2    public static void main(String[] args) {
      3        RealEstate realEstate = new RealEstate();
      4        DynamicProxy dynamicProxy = new DynamicProxy();
      5        RentHouse proxy = (RentHouse) dynamicProxy.bind(realEstate);
      6        proxy.rent();
      7    }
      8}
      

      在这个例子中,无论是静态代理还是动态代理,代理对象都在真实对象执行租房操作前后增加了额外的行为,如房源展示、合同签订等,体现了代理模式的价值。动态代理相比静态代理更加灵活,可以在运行时动态创建代理对象,无需为每个真实对象都手动创建一个代理类。

行为型模式(Behavioral Patterns)

  1. 责任链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。

  2. 命令模式(Command):将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。

  3. 解释器模式(Interpreter):给定一种语言,定义它的文法和一个解释器,该解释器使用该语法来解释语言中的句子。

  4. 迭代器模式(Iterator):提供一种方法顺序访问一个聚合对象中各个元素,而又不需要暴露该对象的内部表示。

  5. 中介者模式(Mediator):用一个中介者对象来封装一系列的对象交互。

  6. 备忘录模式(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

  7. 观察者模式(Observer) :定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。

    1. 观察者模式解决了什么问题?

      1. 对象间一对多的依赖关系:在软件系统中,当一个对象的状态发生变化时,其他依赖于它的对象也都需要得到通知并被自动更新。这种情况下,如果采用传统的直接调用方式,对象间的耦合度会非常高,不利于代码的维护和扩展。观察者模式通过引入"主题"和"观察者"的概念,使得对象间的依赖关系变得清晰且灵活。

      2. 解耦:通过将依赖关系抽象为主题和观察者之间的订阅/发布关系,观察者模式降低了对象之间的耦合度。这使得代码更加易于维护和扩展,因为你可以在不修改主题对象代码的情况下,增加或删除观察者对象。

      3. 异步通信:观察者模式支持异步通信,即主题对象在状态改变时,可以立即通知观察者,而观察者可以在稍后的时间处理这个通知。这种异步通信的方式可以提高系统的响应速度,减少不必要的等待时间。

      4. 广播通知 :当主题对象的状态发生变化时,它可以通过调用notifyObservers()方法一次性通知所有注册的观察者对象,而不需要分别调用每个观察者的更新方法。这种广播通知的方式大大提高了代码的效率和可维护性。

      5. 支持动态关联 :观察者模式允许在运行时动态地建立或断开对象之间的依赖关系。这意味着你可以在程序运行的任何时刻,通过调用registerObserver()removeObserver()方法来添加或删除观察者对象。

      6. 事件驱动:观察者模式是一种典型的事件驱动编程模式。在这种模式下,程序的执行流程不是由调用顺序来控制的,而是由事件来驱动的。当某个事件发生时(例如主题对象的状态变化),与该事件相关的所有代码(即观察者的更新方法)都会被自动执行。这种编程方式使得代码更加清晰、易于理解和维护。

    2. 代码案例:

      java 复制代码
      // 主题接口  
      interface Subject {  
          void registerObserver(Observer o);  
          void removeObserver(Observer o);  
          void notifyObservers();  
          // 假设这里有一个状态值  
          void setState(String state);  
          String getState();  
      }  
        
      // 观察者接口  
      interface Observer {  
          void update(String state);  
      }  
        
      // 具体主题类  
      class ConcreteSubject implements Subject {  
          private List<Observer> observers;  
          private String state;  
        
          public ConcreteSubject() {  
              observers = new ArrayList<>();  
          }  
        
          @Override  
          public void registerObserver(Observer o) {  
              observers.add(o);  
          }  
        
          @Override  
          public void removeObserver(Observer o) {  
              int i = observers.indexOf(o);  
              if (i >= 0) {  
                  observers.remove(i);  
              }  
          }  
        
          @Override  
          public void notifyObservers() {  
              for (Observer observer : observers) {  
                  observer.update(state);  
              }  
          }  
        
          @Override  
          public void setState(String state) {  
              this.state = state;  
              // 每当状态变化,就通知所有的观察者  
              notifyObservers();  
          }  
        
          @Override  
          public String getState() {  
              return state;  
          }  
      }  
        
      // 具体观察者类  
      class ConcreteObserver implements Observer {  
          private String name;  
          private Subject subject;  
        
          public ConcreteObserver(String name, Subject subject) {  
              this.name = name;  
              this.subject = subject;  
              // 初始化时注册自己为观察者  
              this.subject.registerObserver(this);  
          }  
        
          @Override  
          public void update(String state) {  
              System.out.println(name + " observed state change to: " + state);  
          }  
      }  
        
      // 使用示例  
      public class ObserverPatternDemo {  
          public static void main(String[] args) {  
              Subject subject = new ConcreteSubject();  
        
              Observer observer1 = new ConcreteObserver("Observer 1", subject);  
              Observer observer2 = new ConcreteObserver("Observer 2", subject);  
        
              // 改变主题状态  
              subject.setState("New state");  
        
              // 移除一个观察者  
              subject.removeObserver(observer1);  
        
              // 再次改变主题状态  
              subject.setState("Another new state");  
          }  
      }
      1. 或者我们可以用Rxjava框架来写:

        java 复制代码
        import com.sun.media.jfxmediaimpl.MediaDisposer;
        import io.reactivex.rxjava3.annotations.NonNull;
        import io.reactivex.rxjava3.core.Observable;
        import io.reactivex.rxjava3.core.Observer;
        import io.reactivex.rxjava3.disposables.Disposable;
        
        
        public class ResultTest {
            public static void main(String[] args) {
                // 创建一个Observable(被观察者),它发射从1到5的整数序列
                Observable<Integer> observable = Observable.just(1, 2, 3, 4, 5);
        
                // 创建一个Observer(观察者),它订阅Observable并处理接收到的数据
                Observer<Integer> observer = new Observer<Integer>() {
        
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        System.out.println("开始订阅数据...");
                    }
        
                    @Override
                    public void onNext(Integer value) {
                        System.out.println("接收到数据:" + value);
                    }
        
                    @Override
                    public void onError(Throwable e) {
                        System.out.println("数据接收出错:" + e.getMessage());
                    }
        
                    @Override
                    public void onComplete() {
                        System.out.println("数据接收完毕!");
                    }
                };
        
                // Observer订阅Observable
                observable.subscribe(observer);
            }
        }
  8. 状态模式(State):允许一个对象在其内部状态改变时改变它的行为。

  9. 策略模式(Strategy):定义一系列算法,把它们一个个封装起来,并使它们可以相互替换。

  10. 模板方法模式(Template Method):定义一个操作中的算法骨架,而将一些步骤延迟到子类中实现。

  11. 访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作。

相关推荐
哪 吒1 小时前
最简单的设计模式,抽象工厂模式,是否属于过度设计?
设计模式·抽象工厂模式
Theodore_10221 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
转世成为计算机大神4 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
小乖兽技术5 小时前
23种设计模式速记法
设计模式
小白不太白9507 小时前
设计模式之 外观模式
microsoft·设计模式·外观模式
小白不太白9507 小时前
设计模式之 原型模式
设计模式·原型模式
澄澈i7 小时前
设计模式学习[8]---原型模式
学习·设计模式·原型模式
小白不太白95014 小时前
设计模式之建造者模式
java·设计模式·建造者模式
菜菜-plus16 小时前
java 设计模式 模板方法模式
java·设计模式·模板方法模式
萨达大16 小时前
23种设计模式-模板方法(Template Method)设计模式
java·c++·设计模式·软考·模板方法模式·软件设计师·行为型设计模式