1. Separating out the things that change from those that stay the same.
Obviously, we do it to avoid the tight coupled code, get it easy to make changes with less cost. At first time when we put down your fingers to write methods, we should recognise what change from what stay the same. For example:
class Animal
def make_sound
end
end
As you can see, the make_sound method here will be changed regularly. It relies on what kind of animal. The animal could be dog or cat or bird. They have different sounds. So, at first we notice that make_sound is changeable. Hence, we pull out this method to isolate it from the certain code.
2. Program to an interface, not an implementation
If we have the tree of inheritances like this A -> B -> C -> D -> E -> F -> … Z. If A can do the same things, we shouldn’t involve methods of B … Z (A is superclass).
- Carefully abstract out all the important functionality into many separate interfaces.
- Program to the most general type you can
- Reason ruby doesn’t have interfaces -> encourage to program to interfaces. If B inherits A, if A can do things for B so involve methods of A instead of B.
- Reduce the amount of coupling in our code.
# challence
car = Car.new
car.drive(100)
plane = Plane.new
plane.fly(1000)
# solution
vehicle1 = Vehicle.new
vehicle1.traval(100)
vehicle2 = Vehicle.new
vehicle2.traval(100)
3. Prefer composition over inheritance
- Inheritance tends to marry the subclass to the superclass, leading to bound the common implementation core (x)
- Superclass is shown in subclass, leading to tight coupled (x)
Solutions:
- Is kind of (x) => has (o)
- Abstracting common methods at base class and refer to #2 if we couldn’t avoid to use inheritance
# Challenge
class Vehicle
# All sorts of vehicle-related code...
def start_engine
# Start the engine
end
def stop_engine
# Stop the engine
end
end
class Car < Vehicle
def sunday_drive
start_engine
# Cruise out into the country and return
stop_engine
end
end
# Solution
class Engine
# All sorts of engine-related code...
def start
# Start the engine
end
def stop
# Stop the engine
end
end
class Car
def initialize
@engine = Engine.new
end
def sunday_drive
@engine.start
# Cruise out into the country and return...
@engine.stop
end
end
4. Delegation
Handing problems off to other objects. Take a look on code at #3, we can see that Car delegates object @engine to do things.