SOLID principle, along with the GRASP, is often seemingly difficult subject to understand especially for beginners. I just have made the good example using Ruby code.
Single Responsibility Principle(SRP)
SRP means a single class has to have only one reason to change. This means a class needs to be clear such that what it does and what it is responsible for.
def EmployeeInfo
def age; end
def sex; end
def hobby; end
def hobby_name; end
def hobby_type; end
def payment_water; end
def payment_laundry; end
end
For instance the above Ruby code shows a class, intentionally or not, contains methods which is not that directly related to the class definition. Employee, though it can have hobby, but the hobby detail hobby_name and hobby_type is not directly related. So for instance, if we are going to change hobby_type and if it does effect hobby_name, that causes verbosity since it is the modification of HOBBY. This is just an simple example, but often voilerplate coding enhances too much methods and params in a single class, which makes class hard to read, hard to define what is going on, and such non-modularity is going to harm the entire process if we need to add/modify something in it. This means, the responsibility in each code block is not clear. So I rather do this:
-----
def Employee
def age; end
def sex; end
def hobby
Hobby.new(@key)
end
end
def Hobby
def initialize(key)
@key = key
end
def name
end
def type
end
end
...
This case, since Hobby has bunch of its attribute those are specific to that "Hobby" object, now it has been separated as a single class. With this definition, if something inner attribute or function in Hobby object altered, it does not affect Employee anymore, since these two are low-coupled and mutually independent, and connect with each other via the interface.
Open/Closed Principle
Open-Closed Principle is "Open for extension, Closed for modification." For instance,
def Car
def body; end
def tire; end
def shaft; end # stable and less likely to change
def gear; end # stable and less likely to change
end
This case, we no longer need to expose shaft and gear to public, since these two are already stable and it is less likely that those shaft and gear is going to change so far.
def Car
def body; end
def tire; end
private
def shaft; end # stable and less likely to change
def gear; end # stable and less likely to change
end
With this in mind, we can hide which is not necessary to expose for modification. Also, those classes need to be easy to be extended.
def Wagon < Car
def body
RectangledAndBigger
end
def tire
LittleBitBigger
end
end
Then just an addition of inherited class realized the requirement of new Wagon, which is the business need. If your codebase is not that open for addition and if all of the components(or non-component) are not clear whether it could be altered or not, developers are going to be messed up.
Liskov Substitution Principle
This is so easy to show an example. Under Liskov Substitution Principle, the parent class and child class (or the classes of the same Level inheriting from the same class, of course) needs to be INTERCHANGEABLE such that those interfaces(I mean, methods and values) are the same. For instance, the class String in Ruby has to_i (in general toInt) method to convert the value's type into integer.
irb> "moomin".to_i
=> 0
irb> 99.to_i
=> 99
irb> 99.99.to_i
=> 100
This is possible since these String, Integer, Float inherit from the same Object class.
Interface Segregation Principle
Just let's look at the example:
def SoftDrink
def sugar; end
def water; end
def can; end
def size; end
...
end
So that
def Pepsi < SoftDrink
end
If the SoftDrink is Pepsi, this makes sense and the class SoftDrink deserves to be its parent class to inherit from. However, how about this???
def NonSugarGreenTea < SoftDrink
def leaves; end
end
It is obvious that we do not need SUGAR of SoftDrink class to inherit from. This is not nice since NonSugarGreenTea is compelled to have sugar as its interface. Also, if the SoftDrink is not contained in Can but PetBottle, also same issue happens. So:
def SoftDrink
def water; end
def size; end
...
end
def Pepsi < SoftDrink
def can
end
end
def NonSugarGreenTea < SoftDrink
def leaves; end
def pet_bottle; end
end
Now intefaces has been segregated and they only potentially have what they only necessary. This is ISP.
Dependency Inversion Principle(DIP)
DIP means Concrete class only should be dependent on the Abstract class and vice versa is not accepted. Since anti-pattern code example explains better, I will show you the bad example below:
def SoftDrink
def some_method
Pepsi.omake
end
end
def Pepsi < SoftDrink
def self.omake
end
end
Just don't do this shit.
So the SOLID Principle is the main principle such that coders keep its codebase clean, less-couple, and easy to change.
No comments:
Post a Comment