設計模式學習筆記(十七)中介者模式及其應用場景

歸斯君發表於2022-04-07

中介者(Mediator)模式:定義了一個單獨的中介物件,來封裝一組物件之間的互動。將這組物件之間的互動委派給與中介物件互動,來避免物件之間的直接互動。比如我們各種裝置之間的通訊,就是通過伺服器作為中介物件來進行互動:

image-20220407094542645

一、中介者模式介紹

中介者又叫做調停模式,是一種物件行為型模式,它降低了物件之間的耦合性,讓物件易於被獨立地呼叫,是迪米特法則的典型應用,下面就來看看中介者模式的結構和實現:

1.1 中介者模式的結構

中介者模式主要通過引入用於協調其他物件或類之間相互呼叫的中介者類,為了讓系統具有具有更好的靈活性和擴充套件性。其結構如下圖所示:

image-20220407115009351

上面的類圖中主要包含以下角色:

  • Mediator:抽象中介者,是中介者的介面/抽象類
  • ConcreteMeditor:中介者的具體實現,實現中介者介面,定義一個List來管理Colleague物件
  • Colleague:抽象同事類,定義同事類的介面/抽象類,儲存中介者物件,實現同事類的公共方法
  • ConcreteColleague1、ConcreteColleague2:具體同事類,實現抽象同事類。通過中介者間接完成具體同事類之間的通訊互動

1.2 中介者模式的實現

根據上面的類圖,可以實現如下程式碼:

  1. 抽象中介者及其實現
/**
 * @description: 中介者抽象類
 * @author: wjw
 * @date: 2022/4/7
 */
public abstract class Mediator {

    /**註冊同事類*/
    public abstract void register(Colleague colleague);

    /**處理接收邏輯*/
    public abstract void operation(Colleague colleague);
}

/**
 * @description: 具體中介者類
 * @author: wjw
 * @date: 2022/4/7
 */
public class ConcreteMediator extends Mediator{

    private List<Colleague> colleagues = new ArrayList<Colleague>();

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

    @Override
    public void operation(Colleague colleague) {
        for (Colleague coll : colleagues) {
            if (!coll.equals(colleague)) {
                coll.receive();
            }
        }
    }
}
  1. 抽象同事類及其實現
/**
 * @description: 抽象同事類
 * @author: wjw
 * @date: 2022/4/7
 */
public abstract class Colleague {

    protected Mediator mediator;

    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    public abstract void receive();

    public abstract void send();
}

/**
 * @description: 具體同事類1
 * @author: wjw
 * @date: 2022/4/7
 */
public class ConcreteColleague1 extends Colleague{

    @Override
    public void receive() {
        System.out.println("具體同事類 ConcreteColleague1 接收請求");
    }

    @Override
    public void send() {
        System.out.println("具體同事類 ConcreteColleague1 傳送請求");
        /*中介者進行轉發*/
        mediator.operation(this);
    }
}

/**
 * @description: 具體同事類2
 * @author: wjw
 * @date: 2022/4/7
 */
public class ConcreteColleague2 extends Colleague{

    @Override
    public void receive() {
        System.out.println("具體同事類 ConcreteColleague2 接收到請求");
    }

    @Override
    public void send() {
        System.out.println("具體同事類 ConcreteColleague2 傳送請求");
        mediator.operation(this);
    }
}
  1. 客戶端測試類
/**
 * @description: 客戶端
 * @author: wjw
 * @date: 2022/4/7
 */
public class Client {
    public static void main(String[] args) {
        Mediator concreteMediator = new ConcreteMediator();
        Colleague concreteColleague1 = new ConcreteColleague1();
        Colleague concreteColleague2 = new ConcreteColleague2();
        concreteMediator.register(concreteColleague1);
        concreteMediator.register(concreteColleague2);
        concreteColleague1.send();
        concreteColleague2.send();

    }
}

測試結果為:

具體同事類 ConcreteColleague1 傳送請求
具體同事類 ConcreteColleague2 接收到請求
具體同事類 ConcreteColleague2 傳送請求
具體同事類 ConcreteColleague1 接收請求

二、中介者模式應用場景

2.1 中介者模式的適用情況

如果遇到以下情況可以考慮使用中介者模式:

  1. 系統中物件之間存在複雜的引用關係,系統結構混亂且難以理解
  2. 一個物件由於引用了其他很多物件並且直接和這些物件通訊,導致難以複用該物件
  3. 需要通過一箇中間類來封裝多個類中的行為,但又不想生成太多的子類

2.2 中介者模式在MVC模式中的應用

比如說,在MVC框架中,控制器(Controller)就是模型(Model)和檢視(View)之間的中介者:

  • Model(模型):代表一個存取物件的資料,有Dao、Bean等等
  • View(檢視):表示所看到的東西,比如網頁、JSP等用於展示模型中的資料
  • Controller(控制器):作用於模型和檢視中間,控制資料流向模型物件,在資料變化時更新檢視

image-20220407153000058

三、中介者模式實戰

3.1 ORM框架

我們知道在Java與資料庫互動中JDBC可以完成對多種資料庫操作,舉一個利用JDBC查詢的例子:

//1.載入MySQL驅動注入到DriverManager
Class.forName("com.mysql.cj.jdbc.Driver");
//2.提供JDBC連線的URL、使用者名稱和密碼
String url = "jdbc:mysql://localhost:3306/test_db?";
String username = "root";
String password = "root";
//3.建立資料庫的連線
Connection connection = DriverManager.getConnection(url, username, password);
//4.建立statement例項
Statement statement = connection.createStatement();
//5.1執行SQL語句,得到ResultSet物件,
String query = "select * from test";  //查詢語句,也可以換成CRUD的其他語句
ResultSet resultSet = statement.executeQuery(query);
while(resultSet.next()){
    //5.2通過ResultSet讀取資料後,將資料轉換成JavaBean物件
} 
//6.關閉連線物件
connection.close();

在上面的步驟中,步驟1~4和6都可以封裝重複執行,但是在第5步中,需要完成關係模型ResultSet到物件模型JavaBean的轉換,而這一部分使用通用的方式封裝這種複雜的轉換是比較困難的,因此有ORM(Object Relational Mapping, 物件-關係對映)框架來解決物件轉換關係模型的對映問題。同時也遮蔽了之前JDBC連線中的重複程式碼,只提供簡單的API供開發人員進行使用。

image-20220407163737476

3.2 利用中介者模式模仿MyBatis核心功能

在本案例中我們通過模仿MyBatis 中核心ORM框架功能,來使用中介者模式。首先來看看ORM框架在資料庫和應用互動中的位置:

image-20220407153504379

從圖中可以看出,ORM框架位於資料庫層和應用層中間,相當於兩者之間的中介。在實際MyBatis 實現過程中,不僅用到了中介者模式,還有工廠模式和建造者模式。

在ORM框架實現的核心類中,包括載入配置檔案、對XML進行解析、獲取資料庫session、運算元據庫以及返回結果等步驟。在ORM內部的結構如下圖所示(來自《重學Java設計模式》):

image-20220407165437935

  • 左上框內是對資料庫的定義和處理,包括<T> T selectOne<T> List<T> selectList等等
  • 右上是對資料庫配置的開啟session的工廠處理類,工廠會操作DefaultSqlSession
  • 最後是核心類SqlSessionFactoryBuilder,它可以實現處理工廠、解析檔案、拿session等操作

下面就來看看具體程式碼

實戰程式碼

  1. 建立對應資料庫、JavaBean和Dao介面

建立資料庫design-mediatro,資料表userschool

image-20220407171710282

參考資料

《重學Java設計模式》

《Java設計模式》

《MyBatis技術內幕》

http://c.biancheng.net/view/1393.html

相關文章