Review the video about the testing, and try to get more from this lecture:
"The Clean Code Talks -- Inheritance, Polymorphism, & Testing"
https://www.youtube.com/watch?v=4F72VULWFvcaction items:
1. put sample code in C#, and then, check in git;
2. write down key words, and easy for review and follow as rules.
Julia's sample code in C#:
Problem statement: 1 + 2*3, how to implement in OO design (using C# language)
Three solutions are provided, naive one, better one, optimal solution to apply S.O. principles.
1. Represent this as a tree
+
/ \
1 *
/ \
2 3
Most of people come out solution like the following:
Using conditionals
class Node{
char operator;
double value;
Node left;
Node right;
double evaluate(){
switch(operator){
case '#': return value;
case '+': return left.evaluate() + right.evaluate();
case '*" return left.evaluate() * right.evaluate();
case ... // edit this for each new operator
}
}
}
Big problem on this:
graphic representation,
Node
op:char
value: double
left: Node
right:Node
--------------
evaluate():double
Julia could not figure out the analysis here <- first time to memorize this analysis, and also try to learn reasoning
Analyzing attributes
# + *
function yes yes
value yes
left yes yes
right yes yes
Two different behaviors are fighting here, (see the above table), not matching Single Responsibility Principle.
if you are the operation node, then you need your left and right child; whereas value node, you just need value.
C# code using conditional implementation, one class Node
Naive approach, breaking single responsibility principle, the C# code is here.
Clean code talk - conditional version written down based on the talk, C# code is here.
2.
Let us break it up:
Node
--------------
evaluate(): double
| |
ValueNode OpNode
value: double op: char
--------------- left: Node
evaluate: double right: Node
----------------
evaluate(): double
As showing above, break Node into ValueNode and OpNode, so ValueNode does not have left and right child because of no meaning over there.
Tree looks like:
OpNode
+
/ \
ValueNode OpNode
1 *
/ \
ValueNode ValueNode
2 3
Operations and values
abstract class Node{
abstract double evaluate();
}
class ValueNode extends Node{
double value;
double evaluate(){
return value;
}
}
class OpNode extends Node{
char operator;
Node left;
Node right;
double evaluate(){
switch(operator) {
case '+': return left.evaluate() + right.evaluate();
case '-': return left.evaluate() + right.evaluate();
case ... // edit this for each new operator
}
}
}
better solution: Node, OpNode, ValueNode, the C# code is here.
3. How to extend this? Every time you add a new operator, need to hold on source code, and add code in switch statement, how to make it better?
OpNode divides into AdditionNode and MultiplicationNode
OpNode
------------------
left: Node
right: Node
------------------
evaluate(): double
AdditionNode MultiplicationNode
---------------------------- --------------------------
evaluate(): double evaluate(): double
abstract class Node{
abstract double evaluate();
}
class ValueNode extends Node{
double value;
double evaluate(){
return value;
}
}
class abstract OpNode extends Node{
Node left;
Node right;
abstract evaluate();
}
Operation classes
class AdditionNode extends OpNode{
double evaluate(){
return left.evaluate() + right.evaluate();
}
}
class MultiplicationNode extends OpNode{
double evaluate(){
return left.evaluate() + right.evaluate();
}
}
Now, the new tree diagram:
AdditionalNode
+
/ \
ValueNode MultiplicationNode
1 *
/ \
ValueNode ValueNode
2 3
optimal solution: Node, OpNode, ValueNode, AdditionNode, MultiplicationNode, here is C# code.
Perfect examples of 1 + 2*3, 3 implementations, Julia learns O of S.O.L.I.D. OO principles, open for extension, close for change.
More detail, the above optimal solution does not have any if statement, and any new arithmetic operation just needs a new class, no need to touch existing code: Node, OpNode, AdditionNode, MultiplicationNode. For example, minus '-' operation, just add MinusNode. For easy to demo, all classes are in one .cs file, but each class should have it's own .cs file. :-)
Share the learning of Open/Close principle - great examples. Cannot wait to move on to next one, Liskov substitution principle!
Reference:
Blog:
http://juliachencoding.blogspot.ca/2015/11/the-clean-code-talks.html
Follow up
Sept. 9, 2018
The project is documented in my github folder, here is the link.
No comments:
Post a Comment