返回 导航

其他

hangge.com

Java - GoF设计模式详解18(中介者模式)

作者:hangge | 2023-06-20 08:55

十八、中介者模式

1,基本介绍

(1)中介者模式(Mediator)用一个中介者对象封装一系列对象交互,以防止这些对象直接交互,从而使这些对象耦合松散,并且可以独立地改变它们的交互。

(2)该模式中包含的角色及其职责如下:
  • 抽象中介者 (Mediator):定义一个接口用于与各同事对象通信。
  • 具体中介者 (ConcreteMediator):实现中介者接口,定义一个同事类的集合,协调各个同事对象的交互关系。
  • 抽象同事类 (Colleague):定义同事的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
  • 具体同事类 (Concrete Colleague):实现同事类的接口,在需要与其他同事对象交互时,通过中介者对象来实现。

2,使用样例

(1)首先我们定义了一个抽象中介者类 Mediator,包含注册同事和转发消息这两个方法:
// 抽象中介者
interface Mediator {
  // 注册同事
  void register(Colleague colleague);
  // 转发消息
  void relay(String message, Colleague colleague);
}

(2)接着定义具体中介者类 ConcreteMediator 实现抽象中介者类,它维护了一个同事列表,并且实现了在中介者中注册同事和转发消息的方法。
// 具体中介者
class ConcreteMediator implements Mediator {
  // 同事列表
  private List<Colleague> colleagues;

  public ConcreteMediator() {
    this.colleagues = new ArrayList<>();
  }

  @Override
  public void register(Colleague colleague) {
    if (!colleagues.contains(colleague)) {
      colleagues.add(colleague);
    }
  }

  @Override
  public void relay(String message, Colleague colleague) {
    colleagues.forEach(c -> {
      if (!c.equals(colleague)) {
        c.receive(message);
      }
    });
  }
}

(3)然后定义一个抽象同事类 Colleague,声明了接收消息和发送消息的方法。
// 抽象同事类
abstract class Colleague {
  // 中介者
  protected Mediator mediator;

  public Colleague(Mediator mediator) {
    this.mediator = mediator;
  }

  // 发送消息
  public abstract void receive(String message);

  // 接收消息
  public abstract void send(String message);
}

(4)接着定义两个具体同事类 ConcreteColleagueAConcreteColleagueB 分别继承了抽象同事类,并实现了接收消息和发送消息的方法。
// 具体同事类A
class ConcreteColleagueA extends Colleague {
  public ConcreteColleagueA(Mediator mediator) {
    super(mediator);
  }

  // 发送消息
  @Override
  public void send(String message) {
    System.out.println("同事A发送消息:" + message);
    mediator.relay(message, this);
  }

  // 接收消息
  @Override
  public void receive(String message) {
    System.out.println("同事A收到消息:" + message);
  }
}

// 具体同事类B
public class ConcreteColleagueB  extends Colleague {
  public ConcreteColleagueB(Mediator mediator) {
    super(mediator);
  }

  // 发送消息
  @Override
  public void send(String message) {
    System.out.println("同事B发送消息:" + message);
    mediator.relay(message, this);
  }

  // 接收消息
  @Override
  public void receive(String message) {
    System.out.println("同事B收到消息:" + message);
  }
}

(5)最后测试一下,们创建了一个具体中介者对象,并创建了两个具体同事对象。然后将这两个同事对象注册到中介者中,并发送消息:
public class Test {
  public static void main(String[] args) {
    // 创建一个具体中介者对象
    Mediator mediator = new ConcreteMediator();
    // 创建了两个具体同事对象
    Colleague colleagueA = new ConcreteColleagueA(mediator);
    Colleague colleagueB = new ConcreteColleagueB(mediator);
    // 将这两个同事对象注册到中介者中
    mediator.register(colleagueA);
    mediator.register(colleagueB);
    // 调用同事 A 的发送消息方法
    colleagueA.send("hangge.com");
    // 调用同事 B 的发送消息方法
    colleagueB.send("航歌");
  }
}

附一:JDK 中的中介者模式

1,Timer 中的中介者模式

(1)在 JDK java.util.Timer 类中,使用了中介者模式来管理定时器任务。java.util.Timer 类维护了一个任务列表,并使用一个线程来调度这些任务。每个任务都是一个 TimerTask 对象,它们之间通过 Timer 对象进行交互。
  • Timer 是中介者,通过 schedule 方法定时调度我们写的各种任务,将任务添加到 TaskQueue 任务队列中,给 TimerThread 执行,让任务与执行线程解耦。
  • TimerTask 是抽象同事类
  • 我们自己写的任务则是具体同事类。

(2)以下是一个使用 java.util.Timer 类的示例:
public class Test {
  public static void main(String[] args) {
    // 初始化Timer定时器对象
    Timer timer = new Timer();

    // 可调度的任务1
    TimerTask task1 = new TimerTask() {
      @Override
      public void run() {
        System.out.println("Task 1 executed.");
      }
    };

    // 可调度的任务2
    TimerTask task2 = new TimerTask() {
      @Override
      public void run() {
        System.out.println("Task 2 executed.");
      }
    };

    // 延迟1秒后执行,之后每2秒定时执行一次
    timer.schedule(task1, 1000, 2000);
    // 延迟2秒后执行,之后每2秒定时执行一次
    timer.schedule(task2, 2000, 2000);
  }
}

2,Executor 接口和 ExecutorService 接口的中介者模式

(1)在 JDKjava.util.concurrent.Executor 接口和 java.util.concurrent.ExecutorService 接口中,使用了中介者模式来管理线程池。这些接口提供了一种通用的方法来执行异步任务,可以将任务提交到线程池中执行,而无需直接创建新的线程。线程池维护了一组工作线程,并使用中介者模式来管理它们之间的交互。

(2)下面是一个使用 java.util.concurrent.ExecutorService 接口创建线程池的示例代码。在这个示例代码中,我们可以看到以下几个角色:
  • ExecutorService 接口是中介者,它负责管理工作线程之间的交互。
  • Executors 类是具体中介者,它实现了 ExecutorService 接口,并提供了一组静态工厂方法来创建线程池。
  • Executor 接口是抽象同事类(Executor 也是的 ExecutorService 父接口),它定义了线程池的基本操作。
  • Runnable 接口是抽象同事类,它定义了任务的基本操作。
  • 匿名内部类是具体同事类,它实现了 Runnable 接口,并被提交给线程池执行。
public class Test {
  public static void main(String[] args) {
    // 创建了一个线程池
    ExecutorService executor = Executors.newFixedThreadPool(5);

    // 提交任务1给线程池执行
    executor.submit(new Runnable() {
      @Override
      public void run() {
        System.out.println("运行任务1");
      }
    });

    // 提交任务2给线程池执行
    executor.submit(new Runnable() {
      @Override
      public void run() {
        System.out.println("运行任务2");
      }
    });

    // 关闭线程池
    executor.shutdown();
  }
}

附二:Spring 中的中介者模式

1,使用 ApplicationContext 来实现中介者模式

(1)在 Spring 中,中介者模式可以通过使用 SpringApplicationContext 来实现。ApplicationContext 可以作为一个中介者,用于在不同的对象之间传递消息。
  • 比如:假设我们有两个 bean,一个是消息生产者,另一个是消息消费者。生产者 bean 在生产消息时,可以将消息发布到 ApplicationContext 中,而消费者 bean 可以监听消息并进行相应的处理。这样,ApplicationContext 就可以在生产者和消费者之间传递消息,作为这两个 bean 之间的中介者。

(2)下面是一个简单的例子,展示了如何使用 ApplicationContext 在两个 bean 之间传递消息。
// 消息生产者
@Component
public class MessageProducer {
    // 注入 ApplicationContext
    @Autowired
    private ApplicationContext applicationContext;

    public void produceMessage(String message) {
        // 发布消息
        applicationContext.publishEvent(new MessageEvent(this, message));
    }
}

// 消息消费者
@Component
public class MessageConsumer {
    // 使用 @EventListener 注解来监听消息
    @EventListener
    public void onMessage(MessageEvent event) {
        String message = event.getMessage();
        // 根据收到的消息执行相应的处理
    }
}

public class MessageEvent extends ApplicationEvent {
    private String message;

    public MessageEvent(Object source, String message) {
        super(source);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

2,使用 JMS 模块来实现中介者模式

(1)JMS (Java Message Service) 是一种 Java 消息中间件,可以在不同的应用之间传递消息。Spring 提供了对 JMS 的支持,可以方便地在 Spring 应用中使用 JMS

(2)关于 JMS 更消息的用法,可以参考我之前写的文章:
评论

全部评论(0)

回到顶部