객체지향/디자인패턴

디자인 패턴을 이용하여 채팅 프로그램을 만드는 과제

desafinado 2023. 12. 10. 09:03
728x90

 

싱글톤 패턴 (Server 클래스): 서버 인스턴스는 애플리케이션 전체에서 하나만 존재해야 함. 이를 보장하기 위해 싱글톤 패턴 사용. getInstance() 메서드를 통해 유일한 서버 인스턴스에 접근.

 

 

옵저버 패턴 (Observer 및 User 클래스): 서버 상태 변화(여기서는 메시지 전송)를 실시간으로 다수의 클라이언트(유저)에게 알리기 위해 사용. User 클래스는 Observer 인터페이스를 구현하여 서버로부터 메시지를 받음.

 

 

빌더 패턴 (MessageBuilder 클래스): 복잡한 문자열(메시지) 생성 과정을 단순화. 메시지를 단계적으로 구축하고, 최종적으로 결합된 메시지를 생성.

#include <iostream>
#include <string>
#include <vector>
#include <list>

// Observer 인터페이스: 상태 변화를 관찰하는 객체들을 위한 인터페이스
class Observer {
public:
    virtual ~Observer() {}
    virtual void update(const std::string& message) = 0;
};

class Server {
private:
    static Server* instance; // 유일한 인스턴스를 저장하는 정적 멤버
    std::list<Observer*> observers; // 관찰자 목록

    Server() {} // private 생성자로 외부 생성 방지

public:
    // 싱글톤 패턴: 인스턴스가 오직 하나만 존재
    static Server* getInstance() {
        if (instance == nullptr) {
            instance = new Server();
        }
        return instance;
    }

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

    void removeObserver(Observer* observer) {
        observers.remove(observer);
    }

    // 옵저버에게 알림: 모든 관찰자에게 메시지 전달
    void notifyObservers(const std::string& message) {
        for (Observer* observer : observers) {
            observer->update(message);
        }
    }
};

Server* Server::instance = nullptr;

class User : public Observer {
private:
    std::string name; // 유저 이름
    Server* server; // 서버 인스턴스

public:
    User(const std::string& name, Server* server) : name(name), server(server) {}

    void sendMessage(const std::string& message) {
        server->notifyObservers(name + ": " + message);
    }

    // 옵저버 패턴: 상태 변화 시 업데이트 메서드 호출
    void update(const std::string& message) override {
        std::cout << name << " received: " << message << std::endl;
    }

    std::string getName() const {
        return name;
    }
};

// UserFactory: 유저 객체 생성을 단순화
class UserFactory {
public:
    static User* createUser(const std::string& name, Server* server) {
        return new User(name, server);
    }
};

// MessageBuilder: 빌더 패턴, 메시지 생성을 위한 클래스
class MessageBuilder {
private:
    std::vector<std::string> messages;

public:
    MessageBuilder& addMessage(const std::string& sender, const std::string& message) {
        messages.push_back(sender + ": " + message);
        return *this;
    }

    std::string build() {
        std::string combinedMessage;
        for (const auto& msg : messages) {
            combinedMessage += msg + "\n";
        }
        return combinedMessage;
    }

    void clear() {
        messages.clear();
    }
};

int main() {
    // 서버 인스턴스 생성
    Server* server = Server::getInstance();

    // 유저 생성
    User* alice = UserFactory::createUser("Alice", server);
    User* bob = UserFactory::createUser("Bob", server);

    // 유저 등록
    server->addObserver(alice);
    server->addObserver(bob);

    // 메시지 빌더 사용
    MessageBuilder messageBuilder;

    messageBuilder.addMessage("Alice", "Hello, everyone!")
                  .addMessage("Bob", "Hi, Alice!");
    alice->sendMessage(messageBuilder.build());

    messageBuilder.clear();

    messageBuilder.addMessage("Bob", "Hello, everyone!")
                    .addMessage("Alice", "Hi, Alice!");
    bob->sendMessage(messageBuilder.build());

    delete alice;
    delete bob;

    return 0;
}
728x90