Logger System 0.1.3
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
adapter_pattern_poc.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
21#include <iostream>
22#include <memory>
23#include <string>
24#include <chrono>
25
26// =============================================================================
27// BEFORE: Conditional Compilation Approach (Current)
28// =============================================================================
29
30#ifdef USE_EXAMPLE_MODE
31
32#include "external_interface.h" // Different header based on mode
33
34class logger_old : public external_interface { // Different base class
35public:
36 void log(const std::string& message) {
37#ifdef MODE_A
38 std::cout << "[Mode A] " << message << std::endl;
39#elif MODE_B
40 std::cout << "[Mode B] " << message << std::endl;
41#else
42 std::cout << "[Default] " << message << std::endl;
43#endif
44 }
45};
46
47#else
48
49class logger_old { // No base class in standalone mode
50public:
51 void log(const std::string& message) {
52 std::cout << "[Standalone] " << message << std::endl;
53 }
54};
55
56#endif
57
58// Problems with above approach:
59// 1. Must recompile for each mode
60// 2. Cannot test all modes with single binary
61// 3. Control flow obscured by preprocessor
62
63// =============================================================================
64// AFTER: Adapter Pattern Approach (Proposed)
65// =============================================================================
66
67// Step 1: Pure core implementation (no external dependencies)
69public:
70 void log_internal(const std::string& message) {
71 // Pure logging logic - same for all modes
72 timestamp_ = std::chrono::system_clock::now();
73 messages_.push_back(message);
74
75 // Simulate logging work
76 std::cout << "[CORE] " << message << std::endl;
77 }
78
79 size_t message_count() const {
80 return messages_.size();
81 }
82
83private:
84 std::vector<std::string> messages_;
85 std::chrono::system_clock::time_point timestamp_;
86};
87
88// Step 2: Adapter base class
90public:
91 explicit logger_adapter(std::shared_ptr<logger_core> core)
92 : core_(std::move(core)) {}
93
94 virtual ~logger_adapter() = default;
95
96 // Delegate to core
97 void log(const std::string& message) {
98 core_->log_internal(message);
99 }
100
101 size_t message_count() const {
102 return core_->message_count();
103 }
104
105protected:
106 std::shared_ptr<logger_core> core_;
107};
108
109// Step 3: Specialized adapters for each integration mode
110
111// Standalone adapter - minimal overhead
113public:
115
116 void log_standalone(const std::string& message) {
117 std::cout << "[Standalone Mode] ";
118 log(message);
119 }
120};
121
122// External interface simulation
124public:
125 virtual ~external_system_interface() = default;
126 virtual void external_log(const std::string& message) = 0;
127 virtual std::string get_interface_name() const = 0;
128};
129
130// Thread system adapter
132 : public logger_adapter
133 , public external_system_interface { // Multiple inheritance OK
134public:
136
137 // Implement external_system_interface
138 void external_log(const std::string& message) override {
139 std::cout << "[Thread System Integration] ";
140 log(message);
141 }
142
143 std::string get_interface_name() const override {
144 return "thread_system::logger_interface";
145 }
146};
147
148// Common system adapter (different interface)
150public:
151 virtual ~common_system_interface() = default;
152 virtual void monitored_log(const std::string& message) = 0;
153 virtual size_t get_metric_count() const = 0;
154};
155
157 : public logger_adapter
158 , public common_system_interface {
159public:
161
162 void monitored_log(const std::string& message) override {
163 std::cout << "[Common System Integration] ";
164 log(message);
166 }
167
168 size_t get_metric_count() const override {
169 return metric_count_;
170 }
171
172private:
173 size_t metric_count_ = 0;
174};
175
176// Full integration adapter (both interfaces)
178 : public logger_adapter
180 , public common_system_interface {
181public:
183
184 void external_log(const std::string& message) override {
185 std::cout << "[Full Integration - External] ";
186 log(message);
187 }
188
189 std::string get_interface_name() const override {
190 return "full_integration";
191 }
192
193 void monitored_log(const std::string& message) override {
194 std::cout << "[Full Integration - Monitored] ";
195 log(message);
196 }
197
198 size_t get_metric_count() const override {
199 return message_count();
200 }
201};
202
203// Step 4: Factory for runtime selection
208 full
209};
210
212public:
213 static std::unique_ptr<logger_adapter> create(integration_mode mode) {
214 auto core = std::make_shared<logger_core>();
215
216 switch (mode) {
218 return std::make_unique<standalone_adapter>(core);
219
221 return std::make_unique<thread_system_adapter>(core);
222
224 return std::make_unique<common_system_adapter>(core);
225
227 return std::make_unique<full_integration_adapter>(core);
228
229 default:
230 throw std::invalid_argument("Unknown integration mode");
231 }
232 }
233};
234
235// =============================================================================
236// Demonstration
237// =============================================================================
238
240 std::cout << "\n=== Adapter Pattern Proof of Concept ===\n" << std::endl;
241
242 // Test 1: Standalone mode
243 {
244 std::cout << "Test 1: Standalone Mode" << std::endl;
246 logger->log("Hello from standalone mode");
247 std::cout << "Messages logged: " << logger->message_count() << "\n" << std::endl;
248 }
249
250 // Test 2: Thread system integration
251 {
252 std::cout << "Test 2: Thread System Integration" << std::endl;
254
255 // Can use as logger_adapter
256 logger->log("Hello as adapter");
257
258 // Can cast to external interface
259 auto* external = dynamic_cast<external_system_interface*>(logger.get());
260 if (external) {
261 external->external_log("Hello via external interface");
262 std::cout << "Interface: " << external->get_interface_name() << std::endl;
263 }
264 std::cout << std::endl;
265 }
266
267 // Test 3: Common system integration
268 {
269 std::cout << "Test 3: Common System Integration" << std::endl;
271
272 auto* monitored = dynamic_cast<common_system_interface*>(logger.get());
273 if (monitored) {
274 monitored->monitored_log("Message 1");
275 monitored->monitored_log("Message 2");
276 std::cout << "Metrics collected: " << monitored->get_metric_count() << std::endl;
277 }
278 std::cout << std::endl;
279 }
280
281 // Test 4: Full integration (both interfaces)
282 {
283 std::cout << "Test 4: Full Integration" << std::endl;
285
286 // Use both interfaces
287 auto* external = dynamic_cast<external_system_interface*>(logger.get());
288 auto* monitored = dynamic_cast<common_system_interface*>(logger.get());
289
290 if (external && monitored) {
291 external->external_log("Via external interface");
292 monitored->monitored_log("Via monitoring interface");
293 std::cout << "Total messages: " << monitored->get_metric_count() << std::endl;
294 }
295 std::cout << std::endl;
296 }
297
298 // Test 5: Runtime mode switching (same binary!)
299 {
300 std::cout << "Test 5: Runtime Mode Switching" << std::endl;
301 std::cout << "All modes tested with SINGLE BINARY" << std::endl;
302 std::cout << "No recompilation needed!" << std::endl;
303 }
304}
305
306// Performance comparison
308 std::cout << "\n=== Performance Comparison ===\n" << std::endl;
309
310 const int iterations = 1000000;
311 auto core = std::make_shared<logger_core>();
312
313 // Direct call (no virtual)
314 {
315 auto start = std::chrono::high_resolution_clock::now();
316 for (int i = 0; i < iterations; ++i) {
317 core->log_internal("test");
318 }
319 auto end = std::chrono::high_resolution_clock::now();
320 auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
321 std::cout << "Direct call: " << duration.count() / iterations << " ns/call" << std::endl;
322 }
323
324 // Virtual call through adapter
325 {
326 auto adapter = std::make_unique<standalone_adapter>(core);
327 auto start = std::chrono::high_resolution_clock::now();
328 for (int i = 0; i < iterations; ++i) {
329 adapter->log("test");
330 }
331 auto end = std::chrono::high_resolution_clock::now();
332 auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
333 std::cout << "Virtual call: " << duration.count() / iterations << " ns/call" << std::endl;
334 std::cout << "Overhead: ~1-2ns (negligible for I/O operations)" << std::endl;
335 }
336}
337
338int main() {
341
342 std::cout << "\n=== Benefits Summary ===" << std::endl;
343 std::cout << "✅ Single binary for all modes" << std::endl;
344 std::cout << "✅ Runtime mode selection" << std::endl;
345 std::cout << "✅ Easier testing (no recompilation)" << std::endl;
346 std::cout << "✅ Clear code structure" << std::endl;
347 std::cout << "✅ Minimal performance overhead" << std::endl;
348 std::cout << "✅ Better maintainability" << std::endl;
349
350 return 0;
351}
void benchmark_overhead()
int main()
void demonstrate_adapters()
void monitored_log(const std::string &message) override
size_t get_metric_count() const override
virtual ~common_system_interface()=default
virtual size_t get_metric_count() const =0
virtual void monitored_log(const std::string &message)=0
virtual std::string get_interface_name() const =0
virtual void external_log(const std::string &message)=0
virtual ~external_system_interface()=default
void external_log(const std::string &message) override
size_t get_metric_count() const override
void monitored_log(const std::string &message) override
std::string get_interface_name() const override
virtual ~logger_adapter()=default
void log(const std::string &message)
std::shared_ptr< logger_core > core_
size_t message_count() const
logger_adapter(std::shared_ptr< logger_core > core)
void log_internal(const std::string &message)
std::vector< std::string > messages_
std::chrono::system_clock::time_point timestamp_
size_t message_count() const
static std::unique_ptr< logger_adapter > create(integration_mode mode)
void log(const std::string &message)
void log_standalone(const std::string &message)
std::string get_interface_name() const override
void external_log(const std::string &message) override