-
Notifications
You must be signed in to change notification settings - Fork 1
/
OCP.java
138 lines (109 loc) · 3.65 KB
/
OCP.java
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
// Open-Closed Principle (OCP) + Specification design pattern
package solidprinciples.ocp;
import java.util.List;
import java.util.stream.Stream;
enum Color {
RED, GREEN, BLUE
}
enum Size {
SMALL, MEDIUM, LARGE, HUGE
}
class Product {
public String name;
public Color color;
public Size size;
public Product(String name, Color color, Size size) {
this.name = name;
this.color = color;
this.size = size;
}
}
class ProductFilter {
public Stream<Product> filterByColor(List<Product> products, Color color) {
return products.stream().filter(p -> p.color == color);
}
// Violating OCP by creating new filters in class that has been already made
public Stream<Product> filterBySize(List<Product> products, Size size) {
return products.stream().filter(p -> p.size == size);
}
public Stream<Product> filterBySizeAndColor(
List<Product> products,
Size size,
Color color
) {
return products.stream().filter(p -> p.size == size
&& p.color == color);
}
}
// Specification design pattern starts here (generic approach!)
interface Specification<T> {
boolean isSatisfied(T item);
}
interface Filter<T> {
Stream<T> filter(List<T> items, Specification<T> spec);
}
class BetterFilter implements Filter<Product> {
@Override
public Stream<Product> filter(List<Product> items, Specification<Product> spec) {
return items.stream().filter(p -> spec.isSatisfied(p));
}
}
class ColorSpecification implements Specification<Product> {
private Color color;
public ColorSpecification(Color color) {
this.color = color;
}
@Override
public boolean isSatisfied(Product item) {
return item.color == color;
}
}
class SizeSpecification implements Specification<Product> {
private Size size;
public SizeSpecification(Size size) {
this.size = size;
}
@Override
public boolean isSatisfied(Product item) {
return item.size == size;
}
}
class AndSpecification<T> implements Specification<T> {
private Specification<T> first, second;
public AndSpecification(Specification<T> first, Specification<T> second) {
this.first = first;
this.second = second;
}
@Override
public boolean isSatisfied(T item) {
return first.isSatisfied(item) && second.isSatisfied(item);
}
}
class OCPDemo {
public static void main(String[] args) {
Product apple = new Product("Apple", Color.GREEN, Size.SMALL);
Product tree = new Product("Tree", Color.GREEN, Size.LARGE);
Product house = new Product("House", Color.BLUE, Size.LARGE);
List<Product> products = List.of(apple, tree, house);
// Old way that violates OCP
ProductFilter pf = new ProductFilter();
System.out.println("Green products (old way):");
pf.filterByColor(products, Color.GREEN)
.forEach(p -> System.out.println(
" - " + p.name + " is green."));
// New way
BetterFilter bf = new BetterFilter();
System.out.println("Green products (new way):");
bf.filter(products, new ColorSpecification(Color.GREEN))
.forEach(p -> System.out.println(
" - " + p.name + " is green."));
// Checking two items
System.out.println("Large blue items:");
bf.filter(products, new AndSpecification<>(
new ColorSpecification(Color.BLUE),
new SizeSpecification(Size.LARGE)
))
.forEach(p -> System.out.println(
" - " + p.name + " is large and blue."));
}
}