-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathConceptualExample.cpp
More file actions
152 lines (121 loc) · 4.23 KB
/
Copy pathConceptualExample.cpp
File metadata and controls
152 lines (121 loc) · 4.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// ===========================================================================
// ConceptualExample.cpp - Adapter Pattern
// ===========================================================================
#include <algorithm>
#include <cassert>
#include <format>
#include <memory>
#include <print>
#include <string>
namespace ConceptualExample_Adapter_Pattern {
/**
* ITarget defines the domain-specific interface used by the client code
*/
class ITarget
{
public:
virtual ~ITarget() = default;
[[nodiscard]]
virtual std::string request() const = 0;
};
/**
* Target implements ITarget - implementation usable by the client code
*/
class Target final : public ITarget
{
public:
[[nodiscard]]
std::string request() const override
{
return "Target: The target's default behavior.";
}
};
/**
* The Adaptee contains some useful behavior,
* but its interface is incompatible with the existing client code.
* The Adaptee needs some adaptation before the client code can use it.
*/
class Adaptee
{
public:
Adaptee() = default;
[[nodiscard]]
std::string specificRequest() const
{
constexpr std::string_view response{ ".eetpadA eht fo roivaheb laicepS" };
return std::string{ response };
}
};
/**
* The Adapter translates the Target interface expected by the client
* into calls to the Adaptee interface.
*/
class Adapter final : public ITarget
{
private:
std::unique_ptr<Adaptee> m_adaptee;
/**
* It's a personal design decision, whether `std::unique_ptr` is actually necessary,
* or if a direct member (`Adaptee m_adaptee`) could make
* the example even more modern and efficient. It depends, among other things,
* on the size of the adaptee object:
*
* Adaptee m_adaptee;
*/
public:
explicit Adapter(std::unique_ptr<Adaptee> adaptee)
: m_adaptee{ std::move(adaptee) }
{
assert(m_adaptee);
}
[[nodiscard]]
std::string request() const override {
std::string original{ m_adaptee->specificRequest() };
std::reverse(original.begin(), original.end());
return std::format("Adapter: (TRANSLATED) {}", original);
}
/**
* The adapter does own a `std::unique_ptr` object,
* therefore I make the adapter move-only.
*/
Adapter(const Adapter&) = delete;
Adapter& operator=(const Adapter&) = delete;
Adapter(Adapter&&) noexcept = default;
Adapter& operator=(Adapter&&) noexcept = default;
};
/**
* The client code supports all classes that follow the Target interface.
* Passed as a const reference, since the client does not need to own the object.
*/
static void clientCode(const ITarget& target) {
std::string response{ target.request() };
std::println("{}", response);
}
static void test_conceptual_example_01() {
auto adapter =
std::make_unique<Adapter>(
std::make_unique<Adaptee>()
);
clientCode(*adapter);
}
static void test_conceptual_example_02() {
std::println("Client: I can work fine with the Target object:");
auto target = std::make_unique<Target>();
clientCode(*target);
auto adaptee = std::make_unique<Adaptee>();
std::println("Client: The Adaptee class has an incompatible interface:");
std::string specificResponse = adaptee->specificRequest();
std::println("Adaptee: {}", specificResponse);
std::println("Client: But I can work with the Adaptee via the Adapter:");
auto adapter = std::make_unique<Adapter>(std::move(adaptee));
clientCode(*adapter);
}
}
void test_conceptual_example() {
using namespace ConceptualExample_Adapter_Pattern;
test_conceptual_example_01();
test_conceptual_example_02();
}
// ===========================================================================
// End-of-File
// ===========================================================================