Repository navigation
Expand file tree
/
Copy pathopen_closed_principle.cpp
More file actions
143 lines (126 loc) · 3.89 KB
/
Copy pathopen_closed_principle.cpp
File metadata and controls
143 lines (126 loc) · 3.89 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
/***
Acknowledagement: This is a lecture note for course https://www.udemy.com/course/patterns-cplusplus/ by
@Dmitri Nesteruk
Title: Open-Close-Principle
Task: The task is to design a product filter that can select some products,
the code should meet Open-Close-Principle so we can easily extend the code
to change the filter criterion or the product type without modify the code
we already wrote.
Shiyu Mou
***/
#include <string>
#include <vector>
#include <iostream>
using namespace std;
enum class Color {red, green, blue};
enum class Size {small, medium, large};
struct Product
{
string name;
Color color;
Size size;
};
/*** bad example, break OCP, not extentable and have to modify this part of
code if a change is required ***/
struct ProductFilter
{
typedef vector<Product*> Items;
// here we have to add 3 different functions in this filter code
Items by_color(Items items, const Color color){
Items results;
for (auto& i: items)
if (i->color==color)
results.push_back(i);
return results;
}
Items by_size(Items items, const Size size){
Items results;
for (auto& i: items)
if (i->size==size)
results.push_back(i);
return results;
}
Items by_size_and_color(Items items, const Size size, const Color color){
Items results;
for (auto& i: items)
if (i->size==size && i->color==color)
results.push_back(i);
return results;
}
}; // and too many repeating code
/*** now make a better filter ***/
// first let's have an abstract class called Specification for comparing things
template <typename T>
struct Specification
{
virtual ~Specification() = default;
virtual bool is_satisfied(T* item) const = 0;
};
// subclass Specification to have a color comparator
struct ColorSpecification : Specification<Product>
{
Color color;
explicit ColorSpecification(const Color color): color(color){}
bool is_satisfied(Product* item) const override{
return item->color==color;
}
};
// subclass Specification to have a size comparator
struct SizeSpecification : Specification<Product>
{
Size size;
explicit SizeSpecification(const Size size): size(size){}
bool is_satisfied(Product* item) const override{
return item->size==size;
}
};
// subclass Specification to have a size_and_color comparator
template <typename T>
struct AndSpecification : Specification<T>
{
const Specification<T>& first;
const Specification<T>& second;
AndSpecification(const Specification<T>& first, const Specification<T>& second): first(first), second(second) {}
bool is_satisfied(T* item) const override{
return first.is_satisfied(item) && second.is_satisfied(item);
}
};
// abstract class Filter
template <typename T>
struct Filter
{
virtual void filter(vector<T*> items, Specification<T>& spec, vector<T*> &results) = 0;
virtual ~Filter() = default;
};
// the better filter implementation
struct BetterFilter: Filter<Product>
{
void filter(vector<Product*> items, Specification<Product>& spec, vector<Product*> &results) override{
for (auto& p: items){
if (spec.is_satisfied(p)) results.push_back(p);
}
}
};
int main()
{
Product apple = {"Apple", Color::green, Size::small};
Product tree{"Tree", Color::green, Size::large};
Product house = {"House", Color::blue, Size::large};
const vector<Product*> all{&apple, &tree, &house};
BetterFilter bf;
// Specification by color
ColorSpecification green(Color::green);
vector<Product*> green_things;
bf.filter(all, green, green_things);
for (auto& x : green_things)
cout<<x->name<<" is green\n";
// Specification by size
SizeSpecification large(Size::large);
// Specification by both color and size
AndSpecification<Product> green_large(green, large);
vector<Product*> green_large_things;
bf.filter(all, green_large, green_large_things);
for (auto& x : green_large_things)
cout<<x->name<<" is green and large\n";
return 0;
}