Developing methods of class for other classes to use, that is interface. Interfaces should not change time by time. Because that is what the other classes know about this class. Those are also connections.
Separating interface from implementation equals separating what rarely change from what change regularly. Interfaces should be same. In other words, the knowledge that other classes know about class A should be same. Not exact same but at least those are not changed. Regarding to Open/Close principle we close for changing and open for expanding. Changing and expanding are different.
For example, we have Watch class like below.
class Watch def show_time end private def show_numbers end def show_timekeeper end end
show_time is interface method. Other classes know that we can show time using Watch. That means any Watch's instances which are able to show time. If this system has been running for many years and one day we change show_time to time_show. But show_time is a message that other classes would send to an instance of this class. Now it becomes wrong message. That is bad impact if we don't close for changes. We are able to handle it well but how about big system with a bunch of connections? We even can not do this or going crazy by doing this. It costs time and taking risk.
So we should not change this part. This is interface.
class Watch def show_time end end
It's necessary to say that Naming is very important, especially name for interfaces which should not be changed in future. Every time we code, let's think about interfaces.
- What interfaces are we working on?
- Are we putting implementation to interface?
- Are we changing interface methods?
- What are impacts and boundaries?
Getting back to above code, what we should do if we want to change how it does but not what it is? . Look! WHAT IT IS? is usually about Interface. HOW IT DOES? is the implementation. Implementation is a sign for a thing which change regularly. Programing to interface does not mean we put a bunch of code to interface methods. But that means we uses Interfaces as the main messages, exactly INTERFACE, a port or an electric plug. Implementation would being used by putting code to these interfaces.
Look at above electric plug! People (other classes) don't know exactly where it would go. They have no idea about the electric cables behind which are new or not.
- WHAT IT DOES? - providing electricity.
- HOW IT DOES? - no idea! The person who installed this would know. This plug can be moved to another house and being reused. Interface is same but another implementation (in another house).
That is way of critical thinking in coding and design.
According to above explanation we can implement like this.
class ClassicSkin def show end end class Watch attr_reader :skin def initialize(skin) @skin = skin end def show_time skin.show end end
Now ClassicSkin becomes the implementation of show_time interface. show method is also other interface method which belongs to ClassicSkin. But it can be the implementation for show_time interface method. Or another implementation level here:
class WatchSkin def show_classic end def show_digital end end
Feel free to change show_time implementation by involving different method. By using first solution we can have two classes:
So we use Dependency Injection because this instance can be changed regularly.
However, with second solution, we have only one class WatchSkin with different methods so we even don't need to create instance. We use Isolation by private method.
class Watch def show_time skin.show_classic end def skin @skin ||= WatchSkin.new end end
We use DI because skin changed regularly whenever creating object - it created in constructor initialize method. Thus, we get to know the implementation might change regularly so we should separate them from interface. In order to do that, we have to know what exactly interface and where they are in code.
Thank for reading!