# Blog 5|設計模式 - 行為模式
- Reference :
- https://shengyu7697.github.io/archives/
- https://www.jyt0532.com/
- https://refactoringguru.cn/design-patterns/catalog
## (1) 中介者模式 Mediator
- 最經典的中介者模式應用場景之一就是 `聊天室`
- 定義一個物件,負責協調其他多個物件之間的互動
- 
```c++=
class ChatUser {
private:
std::string name;
ChatRoom* chatRoom;
public:
ChatUser(const std::string& name, ChatRoom* room) : name(name), chatRoom(room) {}
void send(const std::string& message) const {
std::cout << name << " 發送消息: " << message << std::endl;
chatRoom->sendMessage(this, message);
}
void receive(const std::string& message) {
std::cout << name << " 收到消息: " << message << std::endl;
}
};
class ChatRoom{
private:
std::vector<ChatUser*> chatUsers;
public:
void addUser(ChatUser* user) {
chatUsers.push_back(user);
}
void sendMessage(const ChatUser* sender, const std::string& message) {
for (ChatUser* user : chatUsers) {
if (user != sender) {
user->receive(message);
}
}
}
};
// client
int main() {
ChatRoom room;
ChatUser Alice("Alice", &room);
ChatUser Bob("Bob", &room);
room.addUser(&Alice);
room.addUser(&Bob);
Alice.send("Hello, Bob!");
Bob.send("Hi, Alice!");
return 0;
}
```
## (2) 備忘錄模式 Memento
- 讓我們保存某個物件的狀態,隨時恢復到之前的狀態
- 
```c++=
class History {
public:
void push(const string& s) {
datas.push_back(s);
}
string pop() {
if (datas.empty()) return string("");
string lastString = datas.back();
datas.pop_back();
return lastString;
}
private:
std::vector<string> datas;
};
// client
int main() {
string data;
History history;
data.append("123");
history.push(data);
data.append("456");
history.push(data);
data.append("789");
data = history.pop();
data = history.pop();
return 0;
}
```
## (3) 迭代器模式 Iterator
- 遍歷一個集合,又不希望暴露它的內部結構,統一介面
- 
```c++=
class PlaylistIterator {
private:
std::vector<std::string> songs;
int position;
public:
PlaylistIterator(const std::vector<std::string>& songs) : songs(songs), position(0) {}
bool hasNext() override {
return position < songs.size();
}
std::string next() override {
if (hasNext()) {
return songs[position++];
}
return "";
}
};
// client
std::vector<std::string> songs;
auto it = new PlaylistIterator(songs);
while (it->hasNext()) {
std::cout << "Playing: " << it->next() << std::endl;
}
```
## (4) 解釋器模式 Interpreter
- 如同編譯器,主要用來解析語言、處理簡單語法規則的
- 
```c++=
class Expression {
public:
virtual int interpret() = 0;
virtual ~Expression() = default;
};
class Number : public Expression {
int number;
public:
Number(int num) : number(num) {}
int interpret() override {
return number;
}
};
class Add : public Expression {
Expression *left, *right;
public:
Add(Expression* l, Expression* r) : left(l), right(r) {}
int interpret() override {
return left->interpret() + right->interpret();
}
};
// client
int main(void) {
// std::string input = "4 + 3";
Expression* left = new Number(4);
Expression* right = new Number(3);
Expression* add = new Add(left, right);
std::cout << add->interpret() << std::endl;
delete left;
delete right;
delete add;
return 0;
}
```
## (5) 策略模式 Strategy
- 
- 定義一系列的演算法,interface 提供方法介面,將實作封裝在 interface 的 subclass
```c++=
class CompressionStrategy {
virtual void compress(const std::string& filename) = 0;
virtual ~CompressionStrategy() = default;
};
class ZipStrategy : public CompressionStrategy {
void compress(const std::string& filename) override {
std::cout << "使用 ZIP 壓縮 " << filename << " 檔案\n";
}
};
class RarStrategy : public CompressionStrategy {
void compress(const std::string& filename) override {
std::cout << "使用 RAR 壓縮 " << filename << " 檔案\n";
}
};
class Compressor {
private:
std::unique_ptr<CompressionStrategy> strategy;
public:
// set strategy in constructor
Compressor(std::unique_ptr<CompressionStrategy> strategy)
: strategy(std::move(strategy)) {}
// dependency injection
void setStrategy(std::unique_ptr<CompressionStrategy> newStrategy) {
strategy = std::move(newStrategy);
}
void compress(const std::string& filename) {
strategy->compress(filename);
}
};
```
## (6) 狀態模式 State
- 讓物件的行為與其狀態緊密相關,當狀態變化時,行為也會隨之變化
- 在狀態非常多的情況下,可能會讓程式變得繁瑣
- 切換狀態的過程中,可能會有一定的記憶體管理問題
- 
```c++=
class MusicPlayer {
private:
State* state;
public:
MusicPlayer(State* initState) : state(initState) {}
~MusicPlayer() { delete state; }
void setState(State* newState) {
delete state;
state = newState;
}
void play() { state->play(this); }
void pause() { state->pause(this); }
void stop() { state->stop(this); }
};
class State {
public:
virtual void play(MusicPlayer* player) = 0;
virtual void pause(MusicPlayer* player) = 0;
virtual void stop(MusicPlayer* player) = 0;
};
class PlayingState : public State {
public:
void play(MusicPlayer* player) override;
void pause(MusicPlayer* player) override;
void stop(MusicPlayer* player) override;
};
class PausedState : public State {
public:
void play(MusicPlayer* player) override;
void pause(MusicPlayer* player) override;
void stop(MusicPlayer* player) override;
};
class StoppedState : public State {
public:
void play(MusicPlayer* player) override;
void pause(MusicPlayer* player) override;
void stop(MusicPlayer* player) override;
};
```
## (7) 命令模式 Command
- 它將 `Command` 封裝成一個物件
- 
```c++=
class Light {
public:
void turnOn() { std::cout << "Light is On\n"; }
void turnOff() { std::cout << "Light is Off\n"; }
};
class Command {
public:
virtual ~Command() = default;
virtual void execute() = 0;
};
class TurnOnCommand : public Command {
public:
explicit TurnOnCommand(Light* light) : light_(light) {}
void execute() override { light_->turnOn(); }
private:
Light* light_;
};
class TurnOffCommand : public Command {
public:
explicit TurnOffCommand(Light* light) : light_(light) {}
void execute() override { light_->turnOff(); }
private:
Light* light_;
};
```
## (8) 責任鏈模式 Chain Of Responsibility
- 把任務逐層傳遞,直到某個物件可以處理它
- 
```c++=
class Handler {
public:
virtual void handleRequest(int request) {};
virtual Handler* setNext(Handler* handler) {
nextHandler = handler;
return handler;
}
protected:
Handler* nextHandler = nullptr;
};
class ConcreteHandler1 : public Handler {
public:
void handleRequest(int request) override {
if (request < 10) {
std::cout << "ConcreteHandler1 handled request: " << request << std::endl;
} else if (nextHandler) {
nextHandler->handleRequest(request);
} else {
std::cout << "Error" << std::endl;
}
}
};
class ConcreteHandler2 : public Handler {
public:
void handleRequest(int request) override {
if (request >= 10 && request < 20) {
std::cout << "ConcreteHandler2 handled request: " << request << std::endl;
} else if (nextHandler) {
nextHandler->handleRequest(request);
} else {
std::cout << "Error" << std::endl;
}
}
};
// client
int main() {
Handler* handler1 = new ConcreteHandler1();
Handler* handler2 = new ConcreteHandler2();
handler1->setNext(handler2);
handler1->handleRequest(5);
handler1->handleRequest(15);
handler1->handleRequest(25);
return 0;
}
```
```c++=
ConcreteHandler1 handled request: 5
ConcreteHandler2 handled request: 15
Error
```
## (9) 訪問者模式 Visitor
- 在不改變物件結構的情況下,為物件添加新的操作,放在 visitor 上
- 
```c++=
class Circle;
class Rectangle;
class Triangle;
// Added
class AreaCalculator {
public:
void visit(Circle* c);
void visit(Rectangle* r);
void visit(Triangle* t);
int totalArea = 0;
};
class Shape {
public:
virtual void accept(AreaCalculator* visitor) = 0; // Added
virtual ~Shape() {}
};
class Circle : public Shape {
public:
int R;
Circle(int r) : R(r) {};
void accept(AreaCalculator* visitor) { // Added
visitor->visit(this);
}
};
class Rectangle : public Shape {
public:
int W, H;
Rectangle(int w, int h) : W(w), H(h) {};
void accept(AreaCalculator* visitor) { // Added
visitor->visit(this);
}
};
class Triangle : public Shape {
public:
int B, H;
Triangle(int b, int h) : B(b), H(h) {};
void accept(AreaCalculator* visitor) { // Added
visitor->visit(this);
}
};
void AreaCalculator::visit(Circle* c) { // Added
totalArea += 3.14 * c->R * c->R;
}
void AreaCalculator::visit(Rectangle* r) { // Added
totalArea += r->W * r->H;
}
void AreaCalculator::visit(Triangle* t) { // Added
totalArea += 0.5 * t->B * t->H;
}
// client
int main() {
std::vector<Shape*> shapes;
shapes.push_back(new Circle(5));
shapes.push_back(new Rectangle(3, 4));
shapes.push_back(new Triangle(4, 5));
AreaCalculator areaCalculator;
for (auto shape : shapes) {
shape->accept(&areaCalculator);
}
std::cout << areaCalculator.totalArea << std::endl;
return 0;
}
```
## (10) 模板方法模式 Template Method
- 定義了一個演算法的骨架,而將一些通用步驟的實作延遲到子類中
- 
```c++=
class AbstractClass {
public:
void TemplateMethod() const {
Step1();
Step2();
Hook(); // Optional
}
void Step1() const {
std::cout << "Step 1: Common implementation\n";
}
virtual void Step2() const = 0; // pure virtual
virtual void Hook() const {} // optional
virtual ~AbstractClass() = default;
};
class C1 : public AbstractClass {
public:
void Step2() const override {
std::cout << "Step 2: C1\n";
}
void Hook() const override {
std::cout << "Hook: C1\n";
}
};
class C2 : public AbstractClass {
public:
void Step2() const override {
std::cout << "Step 2: C2\n";
}
};
// client
int main() {
C1 obj1;
obj1.TemplateMethod();
std::cout << "\n";
C2 obj2;
obj2.TemplateMethod();
}
```
```c++=
Step 1: Common implementation
Step 2: C1
Hook: C1
Step 1: Common implementation
Step 2: C2
```
## (11) 觀察者模式 Observer
- 當一個物件(被觀察者)發生改變時,所有依賴它的物件(觀察者)都會自動收到通知並更新自己
- notify 可以彈性決定要推播什麼訊息,最極端的就是兩種模式 push跟pull
- push:把所有資料給你,不管你需不需要
- pull:只跟 observer 說我更新了,你需要什麼資料另外自己來看
- 
```c++=
class Subscriber {
private:
std::string name;
public:
Subscriber(const std::string& name) : name(name) {}
void update(const std::string& videoTitle) {
std::cout << name << " received notification: " << videoTitle << std::endl;
}
};
class YouTubeChannel {
private:
std::list<std::shared_ptr<Subscriber>> subscribers;
std::string latestVideo;
public:
void addObserver(std::shared_ptr<Subscriber> subscriber) {
subscribers.push_back(subscriber);
}
void removeObserver(std::shared_ptr<Subscriber> subscriber) {
subscribers.remove(subscriber);
}
void notifyObservers() {
for (const auto& observer : subscribers)
observer->update(latestVideo);
}
void uploadNewVideo(const std::string& videoTitle) {
latestVideo = videoTitle;
notifyObservers();
}
};
```