Skip to content

Commit 55e3908

Browse files
authored
Merge pull request mouredev#4701 from hozlucas28/Solution-27-TypeScript
#27 - TypeScript
2 parents 6b90b23 + 038f612 commit 55e3908

File tree

1 file changed

+367
-0
lines changed

1 file changed

+367
-0
lines changed
Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
/*
2+
Open-Close Principle (OCP)...
3+
*/
4+
5+
console.log('Open-Close Principle (OCP)...')
6+
7+
console.log('\nBad implementation of Open-Close Principle (OCP)...')
8+
9+
interface IBadCircle {
10+
radius: number
11+
}
12+
13+
class BadCircle implements IBadCircle {
14+
public radius: number
15+
16+
public constructor({radius}: {radius: number}) {
17+
this.radius = radius
18+
}
19+
}
20+
21+
interface IBadRectangle {
22+
height: number
23+
width: number
24+
}
25+
26+
class BadRectangle implements IBadRectangle {
27+
public height: number
28+
public width: number
29+
30+
public constructor({height, width}: {height: number; width: number}) {
31+
this.height = height
32+
this.width = width
33+
}
34+
}
35+
36+
interface IBadShapeCalculator {
37+
getArea(shape: BadCircle | BadRectangle): number
38+
}
39+
40+
class BadShapeCalculator implements IBadShapeCalculator {
41+
public constructor() {}
42+
43+
public getArea(shape: BadCircle | BadRectangle): number {
44+
if (shape instanceof BadCircle) {
45+
return Math.PI * Math.pow(shape.radius, 2)
46+
} else if (shape instanceof BadRectangle) {
47+
return shape.height * shape.width
48+
} else {
49+
return -1
50+
}
51+
}
52+
}
53+
54+
console.log(`\n\`\`\`\ninterface IBadCircle {
55+
radius: number
56+
}
57+
58+
class BadCircle implements IBadCircle {
59+
public radius: number
60+
61+
public constructor({radius}: {radius: number}) {
62+
this.radius = radius
63+
}
64+
}
65+
66+
interface IBadRectangle {
67+
height: number
68+
width: number
69+
}
70+
71+
class BadRectangle implements IBadRectangle {
72+
public height: number
73+
public width: number
74+
75+
public constructor({height, width}: {height: number; width: number}) {
76+
this.height = height
77+
this.width = width
78+
}
79+
}
80+
81+
interface IBadShapeCalculator {
82+
getArea(shape: BadCircle | BadRectangle): number
83+
}
84+
85+
class BadShapeCalculator implements IBadShapeCalculator {
86+
public constructor() {}
87+
88+
public getArea(shape: BadCircle | BadRectangle): number {
89+
if (shape instanceof BadCircle) {
90+
return Math.PI * Math.pow(shape.radius, 2)
91+
} else if (shape instanceof BadRectangle) {
92+
return shape.height * shape.width
93+
} else {
94+
return -1
95+
}
96+
}
97+
}\n\`\`\``)
98+
99+
console.log(
100+
'\nThis is a bad implementation of Open-Close Principle (OCP),\n' +
101+
'because the method "getArea" of class "BadShapeCalculator" will must change\n' +
102+
'if we have to add more shapes.'
103+
)
104+
105+
console.log('\nGood implementation of Open-Close Principle (OCP)...')
106+
107+
interface Shape {
108+
getArea(): number
109+
}
110+
111+
interface IGoodCircle extends Shape {
112+
radius: number
113+
}
114+
115+
class GoodCircle implements IGoodCircle {
116+
public radius: number
117+
118+
public constructor({radius}: {radius: number}) {
119+
this.radius = radius
120+
}
121+
122+
public getArea(): number {
123+
return Math.PI * Math.pow(this.radius, 2)
124+
}
125+
}
126+
127+
interface IGoodRectangle extends Shape {
128+
width: number
129+
height: number
130+
}
131+
132+
class GoodRectangle implements IGoodRectangle {
133+
public height: number
134+
public width: number
135+
136+
public constructor({height, width}: {height: number; width: number}) {
137+
this.height = height
138+
this.width = width
139+
}
140+
141+
public getArea(): number {
142+
return this.height * this.width
143+
}
144+
}
145+
146+
interface IGoodShapeCalculator {
147+
getArea(shape: Shape): number
148+
}
149+
150+
class GoodShapeCalculator implements IGoodShapeCalculator {
151+
public constructor() {}
152+
153+
public getArea(shape: Shape): number {
154+
return shape.getArea()
155+
}
156+
}
157+
158+
console.log(`\n\`\`\`\ninterface Shape {
159+
getArea(): number
160+
}
161+
162+
interface IGoodCircle extends Shape {
163+
radius: number
164+
}
165+
166+
class GoodCircle implements IGoodCircle {
167+
public radius: number
168+
169+
public constructor({radius}: {radius: number}) {
170+
this.radius = radius
171+
}
172+
173+
public getArea(): number {
174+
return Math.PI * Math.pow(this.radius, 2)
175+
}
176+
}
177+
178+
interface IGoodRectangle extends Shape {
179+
width: number
180+
height: number
181+
}
182+
183+
class GoodRectangle implements IGoodRectangle {
184+
public height: number
185+
public width: number
186+
187+
public constructor({height, width}: {height: number; width: number}) {
188+
this.height = height
189+
this.width = width
190+
}
191+
192+
public getArea(): number {
193+
return this.height * this.width
194+
}
195+
}
196+
197+
interface IGoodShapeCalculator {
198+
getArea(shape: Shape): number
199+
}
200+
201+
class GoodShapeCalculator implements IGoodShapeCalculator {
202+
public constructor() {}
203+
204+
public getArea(shape: Shape): number {
205+
return shape.getArea()
206+
}
207+
}\n\`\`\``)
208+
209+
console.log(
210+
'\nThis is a good implementation of Open-Close Principle (OCP),\n' +
211+
'because the method "getArea" of class "GoodShapeCalculator" will must\n' +
212+
'not change if we have to add more shapes. So, "getArea" is closed to modification\n' +
213+
'but it is open to extension throw any shape which implements "Shape" interface.'
214+
)
215+
216+
console.log(
217+
'\n# ---------------------------------------------------------------------------------- #\n'
218+
)
219+
220+
/*
221+
Additional challenge...
222+
*/
223+
224+
console.log('Additional challenge...')
225+
226+
interface MathOperation {
227+
execute(a: number, b: number): number
228+
}
229+
230+
class AddOperation implements MathOperation {
231+
public constructor() {}
232+
233+
public execute(a: number, b: number): number {
234+
return a + b
235+
}
236+
}
237+
238+
class DivideOperation implements MathOperation {
239+
public constructor() {}
240+
241+
public execute(a: number, b: number): number {
242+
if (b === 0) {
243+
throw new Error('The second parameter must not be zero')
244+
}
245+
246+
return a / b
247+
}
248+
}
249+
250+
class MultiplyOperation implements MathOperation {
251+
public constructor() {}
252+
253+
public execute(a: number, b: number): number {
254+
return a * b
255+
}
256+
}
257+
258+
class SubtractOperation implements MathOperation {
259+
public constructor() {}
260+
261+
public execute(a: number, b: number): number {
262+
return a - b
263+
}
264+
}
265+
266+
interface ICalculator {
267+
addOperation(name: string, operation: MathOperation): this
268+
executeOperation(name: string, a: number, b: number): number
269+
}
270+
271+
class Calculator implements ICalculator {
272+
private operations: Record<string, MathOperation> = {}
273+
274+
public addOperation(name: string, operation: MathOperation): this {
275+
const operationExist: boolean = !!this.operations[name]
276+
if (operationExist) {
277+
throw new Error(`The operation with '${name}' name already exist`)
278+
}
279+
280+
this.operations[name] = operation
281+
return this
282+
}
283+
284+
public executeOperation(name: string, a: number, b: number): number {
285+
const operation: undefined | MathOperation = this.operations[name]
286+
if (!operation) {
287+
throw new Error(`There is not operation with '${name}' name`)
288+
}
289+
290+
return operation.execute(a, b)
291+
}
292+
}
293+
294+
console.log('\nTesting the OCP system without a pow operation...')
295+
296+
const calculator: Calculator = new Calculator()
297+
calculator.addOperation('add', new AddOperation())
298+
calculator.addOperation('divide', new DivideOperation())
299+
calculator.addOperation('multiply', new MultiplyOperation())
300+
calculator.addOperation('subtract', new SubtractOperation())
301+
302+
let a: number = 10
303+
let b: number = 5
304+
305+
console.log(
306+
`\nAdd operation result (${a} + ${b}): ${calculator.executeOperation(
307+
'add',
308+
a,
309+
b
310+
)}`
311+
)
312+
313+
a = 10
314+
b = 2
315+
316+
console.log(
317+
`Divide operation result (${a} / ${b}): ${calculator.executeOperation(
318+
'divide',
319+
a,
320+
b
321+
)}`
322+
)
323+
324+
a = 5
325+
b = 10
326+
327+
console.log(
328+
`Multiply operation result (${a} * ${b}): ${calculator.executeOperation(
329+
'multiply',
330+
a,
331+
b
332+
)}`
333+
)
334+
335+
a = 6
336+
b = 6
337+
338+
console.log(
339+
`Subtract operation result (${a} - ${b}): ${calculator.executeOperation(
340+
'subtract',
341+
a,
342+
b
343+
)}`
344+
)
345+
346+
console.log('\nTesting the OCP system with a pow operation...')
347+
348+
class PowOperation implements MathOperation {
349+
public constructor() {}
350+
351+
public execute(a: number, b: number): number {
352+
return Math.pow(a, b)
353+
}
354+
}
355+
356+
calculator.addOperation('pow', new PowOperation())
357+
358+
a = 2
359+
b = 10
360+
361+
console.log(
362+
`\nPow operation result (${a}^${b}): ${calculator.executeOperation(
363+
'pow',
364+
a,
365+
b
366+
)}`
367+
)

0 commit comments

Comments
 (0)