C++ Adapter 패턴
호환되지 않는 인터페이스를 변환하여 함께 동작할 수 있게 합니다. 클래스 어댑터와 객체 어댑터 방식을 모두 포함합니다.
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <stdexcept>
// ──────────────────────────────────────────────
// 목표 인터페이스: JSON 데이터 소스
// ──────────────────────────────────────────────
class JsonDataSource {
public:
virtual ~JsonDataSource() = default;
virtual std::string fetchJson(const std::string& key) const = 0;
virtual void pushJson(const std::string& key, const std::string& json) = 0;
};
// ──────────────────────────────────────────────
// 레거시 시스템: XML 기반 API (변경 불가)
// ──────────────────────────────────────────────
class LegacyXmlService {
public:
std::string getXmlRecord(const std::string& id) const {
// 실제로는 XML DB 쿼리 수행
return "<record><id>" + id + "</id><value>legacy_data</value></record>";
}
void saveXmlRecord(const std::string& id, const std::string& xml) {
std::cout << "[LegacyXmlService] XML 저장: id=" << id
<< ", data=" << xml << "\n";
}
// XML → 단순 값 추출 (실제에선 파서 사용)
static std::string extractValue(const std::string& xml) {
const std::string tag = "<value>";
auto start = xml.find(tag);
if (start == std::string::npos) return "";
start += tag.size();
auto end = xml.find("</value>", start);
return xml.substr(start, end - start);
}
};
// ──────────────────────────────────────────────
// [객체 어댑터] 컴포지션 방식
// LegacyXmlService를 JsonDataSource 인터페이스로 적응
// ──────────────────────────────────────────────
class XmlToJsonAdapter : public JsonDataSource {
public:
explicit XmlToJsonAdapter(std::shared_ptr<LegacyXmlService> service)
: xmlService_(std::move(service)) {}
// XML 레코드를 가져와 JSON 형태로 변환
std::string fetchJson(const std::string& key) const override {
const auto xml = xmlService_->getXmlRecord(key);
const auto value = LegacyXmlService::extractValue(xml);
// 단순 JSON 직렬화 (실제에선 nlohmann/json 등 사용)
return R"({"key":")" + key + R"(","value":")" + value + R"("})";
}
// JSON을 파싱해 XML로 변환 후 레거시 서비스에 저장
void pushJson(const std::string& key, const std::string& json) override {
// 단순 추출 (실제에선 JSON 파서 사용)
const std::string xml =
"<record><id>" + key + "</id><value>" + json + "</value></record>";
xmlService_->saveXmlRecord(key, xml);
}
private:
std::shared_ptr<LegacyXmlService> xmlService_;
};
// ──────────────────────────────────────────────
// [클래스 어댑터] 다중 상속 방식 (대안)
// 인터페이스와 구현 클래스 모두를 상속
// ──────────────────────────────────────────────
class XmlToJsonClassAdapter : public JsonDataSource, private LegacyXmlService {
public:
std::string fetchJson(const std::string& key) const override {
const auto xml = getXmlRecord(key);
const auto value = extractValue(xml);
return R"({"key":")" + key + R"(","value":")" + value + R"("})";
}
void pushJson(const std::string& key, const std::string& json) override {
const std::string xml =
"<record><id>" + key + "</id><value>" + json + "</value></record>";
saveXmlRecord(key, xml);
}
};
// ──────────────────────────────────────────────
// 클라이언트: JsonDataSource 인터페이스만 알고 있음
// ──────────────────────────────────────────────
void clientCode(JsonDataSource& source) {
source.pushJson("user_001", R"({"name":"홍길동","role":"admin"})");
const auto result = source.fetchJson("user_001");
std::cout << "[클라이언트] 수신한 JSON: " << result << "\n";
}
// ──────────────────────────────────────────────
// 사용 예시
// ──────────────────────────────────────────────
int main() {
std::cout << "=== 객체 어댑터 (컴포지션) ===\n";
auto legacyService = std::make_shared<LegacyXmlService>();
XmlToJsonAdapter objectAdapter(legacyService);
clientCode(objectAdapter);
std::cout << "\n=== 클래스 어댑터 (다중 상속) ===\n";
XmlToJsonClassAdapter classAdapter;
clientCode(classAdapter);
return 0;
}