[第25期] 使用ChatGPT實現C++實現觀察者模式的程式碼/Use ChatGPT to implement Observer Pattern C++ code

本視頻分享如何使用ChatGPT生成觀察者模式C++程式碼的過程。
內容有:

1. 使用ChatGPT實現觀察者模式的C++程式碼
2. 使用VS Code驗證程式碼是否可執行

This video share the process of implementing the observer pattern with ChatGPT.
The content includes:

1. Use ChatGPT to implement Observer Pattern C++ code
2. Verify the generated code in VS code IDE



當使用觀察者模式時,主題物件(Subject)和觀察者物件(Observer)之間存在著一對多的關係。主題物件負責維護一個或多個觀察者物件,並在自身狀態改變時通知所有的觀察者進行更新。

#include <iostream>
#include <vector>
#include <algorithm>

// 主題 (Subject) 類別
class Subject {
public:
  virtual void setState(int state) = 0;
  virtual int getState() const = 0;
  virtual void attach(Observer* observer) = 0;
  virtual void detach(Observer* observer) = 0;
  virtual void notify() = 0;
};

// 具體主題 (Concrete Subject) 類別
class ConcreteSubject : public Subject {
public:
  void setState(int state) override {
    this->state = state;
    notify(); // 當狀態改變時,通知所有觀察者
  }

  int getState() const override {
    return state;
  }

  void attach(Observer* observer) override {
    observers.push_back(observer);
  }

  void detach(Observer* observer) override {
    auto it = std::find(observers.begin(), observers.end(), observer);
    if (it != observers.end()) {
      observers.erase(it);
    }
  }

  void notify() override {
    for (auto observer : observers) {
      observer->update();
    }
  }

private:
  int state;
  std::vector<Observer*> observers;
};

// 觀察者 (Observer) 類別
class Observer {
public:
  virtual void update() = 0;
};

// 具體觀察者 (Concrete Observer) 類別
class ConcreteObserver : public Observer {
public:
  ConcreteObserver(Subject* subject) : subject(subject) {
    subject->attach(this); // 在建構子中註冊到主題物件中
  }

  ~ConcreteObserver() {
    subject->detach(this); // 在解構子中從主題物件中取消註冊
  }

  void update() override {
    int state = subject->getState();
    std::cout << "Observer got notified. New state: " << state << std::endl;
  }

private:
  Subject* subject;
};

int main() {
  ConcreteSubject concreteSubject; // 創建具體主題物件
  ConcreteObserver observer1(&concreteSubject); // 創建第一個觀察者物件並註冊到主題物件中
  ConcreteObserver observer2(&concreteSubject); // 創建第二個觀察者物件並註冊到主題物件中

  concreteSubject.setState(42); // 設定主題物件的狀態,所有觀察者都會得到通知並更新

  return 0;
}

以下是程式碼的說明:
  1. Subject 類別:這是主題物件的抽象類別,定義了主題物件應具備的方法,包括 setState() 用來設定主題物件的狀態、getState() 用來取得主題物件的狀態、attach() 用來註冊觀察者物件、detach() 用來取消註冊觀察者物件、notify() 用來通知所有觀察者進行更新。

  2. ConcreteSubject 類別:這是具體主題物件的實作類別,繼承自 Subject 類別。它實現了 Subject 類別中的方法,包括管理觀察者物件的容器(這裡使用 std::vector),並在狀態改變時通知所有的觀察者進行更新。

  3. Observer 類別:這是觀察者物件的抽象類別,定義了觀察者物件應具備的方法,包括 update() 用來進行更新。

  4. ConcreteObserver 類別:這是具體觀察者物件的實作類別,繼承自 Observer 類別。它實現了 Observer 類別中的 update() 方法,當接收到主題物件的通知時,會執行 update() 方法進行更新。

  5. main() 函式:這是程式的進入點,示範如何使用觀察者模式。在 main() 函式中,我們創建了一個具體主題物件 concreteSubject,並創建了兩個具體觀察者物件 observer1observer2,並將它們註冊到主題物件中。接著,我們使用 setState() 方法設定主題物件的狀態為 42,主題物件會通知所有的觀察者進行更新,觀察者物件的 update() 方法會被呼叫,顯示出新的狀態值。

  6. 最後,程式碼示範了如何使用觀察者模式來實現主題物件和觀察者物件之間的互動。在主題物件中,我們可以透過 attach() 方法將觀察者物件註冊到主題物件,並透過 detach() 方法取消註冊觀察者物件。當主題物件的狀態發生改變時,會呼叫 notify() 方法通知所有已註冊的觀察者物件進行更新。
  7. 觀察者物件則需要實現 update() 方法,用來接收主題物件的通知並進行相應的更新操作。在示範程式碼中,ConcreteObserver 類別的 update() 方法會簡單地印出新的狀態值。

    觀察者模式的優點包括了減少物件間的耦合度,使主題物件和觀察者物件可以獨立演化,並且可以輕鬆地新增或移除觀察者物件,以達到動態的註冊和通知。觀察者模式適合在需要監聽和響應物件狀態改變的情境中使用,例如事件處理、UI更新等。

    需要注意的是,在實際應用中,可以根據需求進行進一步的優化和擴展,例如使用不同的容器來管理觀察者物件、加入訂閱和取消訂閱的機制、支援多種通知方式等,以符合實際情境的需求。



[說明]

1. 請說明std::vector<Observer*> observers的意思

在 C++ 中,std::vector<Observer*> observers 是一個標準庫中的容器類型 std::vector,用來儲存指向 Observer 物件的指標。

解釋:
std::vector:是 C++ 標準庫提供的一個動態陣列容器,可以動態調整大小,並且支援隨機存取,是一種常用的容器類型。
<Observer*>:是 std::vector 中的型別參數,表示該容器中存放的元素型別是 Observer*,即指向 Observer 物件的指標。
observers:是容器的名稱,可以根據需求自行命名。

在觀察者模式中,主題通常需要儲存它的觀察者,因此使用 std::vector 來存放觀察者的指標是一種常見的做法。這樣可以方便地動態添加、刪除和存取觀察者,並且能夠在主題狀態變化時遍歷並通知所有的觀察者進行更新。需要注意的是,由於 std::vector 存放的是指標,因此在使用時需要注意指標的生命週期,避免指標失效或者內存泄漏等問題。

2. 請說明auto it = std::find(observers.begin(), observers.end(), observer);

這段程式碼使用了 C++ 標準庫中的 std::find 算法,來在 observers 容器中搜尋指定的 observer 物件。

解釋:
std::find:是 C++ 標準庫中的一個算法,位於 <algorithm> 標頭檔中,用來在指定範圍內搜尋指定值或滿足指定條件的元素。
observers.begin():是 observers 容器的開始迭代器,指向容器的第一個元素。
observers.end():是 observers 容器的結束迭代器,指向容器的最後一個元素之後的位置。
observer:是要搜尋的目標觀察者物件,這裡假設是一個指向 Observer 物件的指標。

std::find 會從 observers 容器的開始迭代器到結束迭代器之間進行線性搜索,找尋與 observer 物件相等的元素。如果找到了相等的元素,則會返回指向該元素的迭代器;如果找不到,則會返回結束迭代器 (observers.end())。

這段程式碼的目的可能是要找尋 observers 容器中是否存在指向特定 observer 物件的指標。如果 it 等於 observers.end(),表示在容器中沒有找到相等的元素,即指定的 observer 不在容器中;如果 it 不等於 observers.end(),表示找到了相等的元素,即指定的 observer 在容器中。可以根據 it 的值來進一步處理相應的邏輯,例如移除該觀察者或者執行其他操作。

3. 請問auto的用法

在 C++ 中,auto 是一個關鍵字,用來讓編譯器自動推斷變數的型別。使用 auto 可以讓程式碼更加簡潔、易讀,並且減少型別錯誤的發生。

留言

這個網誌中的熱門文章

使用VS code開發Python程式 - Matplotlib繪圖

使用Pycharm開發Python程式與用Matplotlib繪圖

[Python][tkinter] Build tkinter GUI 使用tkinter建立圖形視窗