About Object Oriented Programming

Object-oriented programming is believed to be based on three pillars that provide the programmer with advantages over the procedural approach. They are encapsulation, inheritance, and polymorphism.Inheritance allows you to significantly get rid of code duplication when using the object-oriented approach. But using it, you should always remember about one of the principles of SOLID, called Liskov Substitution, which, unless you go into details, states that inheritance should be used only as an implementation of the “is” relationship. That is, the class of the descendant must "be" a subspecies of the parent. For example, you might have the Bird class and its subclasses Sparrow (sparrow) and Raven (raven), which, for example, inherit (and can extend or modify) the fly method. However, if you create a descendant of Bird called Penguin (penguin) and its fly method, for example, throws an exception (because penguins do not fly), this will violate the Liskov Substitution principle. Speaking of inheritance,It is also worth mentioning one important principle that the Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides) adheres to in his book Design Patterns: Elements of Reusable Object-Oriented Software (1994), which states that you should try use composition (when one object “contains” another object) instead of inheriting as much as possible. Actually, many of the design patterns invented by the “Gang of Four” are precisely based on this principle.Actually, many of the design patterns invented by the “Gang of Four” are precisely based on this principle.Actually, many of the design patterns invented by the “Gang of Four” are precisely based on this principle.

In general, in practice, inheritance is used not to say so often, even despite the fact that in most cases good programmers replace it with a composition. More often there are multiple implementations of one interface, which are specified as dependencies in client classes. Which in turn allows you to use the second pillar of OOP - polymorphism. Which allows you to pass different dependency implementations to client code. Due to the fact that the transmitted dependencies have the same interface, the client (depending on the interface) doesn’t care what object came to it and this allows the programmer to change, during the execution of the program, in what way (which implementation of the interface) the final task will be solved. Speaking of OOP, one cannot but mention encapsulation. This is an essential element of OOP,which provides the ability to create abstractions to hide low-level implementation details while reducing development complexity. Implementation details are hidden by access modifiers to methods such as private and protected. When creating classes, you need to create them so that their interfaces (accessible public methods) provide a consistent abstraction,otherwise it is no longer OOP (!) . For example, let's assume that we are developing a program that controls the cooling system of a nuclear reactor. Then the agreed abstraction of the interface can look as follows.

CoolingSystem::getTemperature()
CoolingSystem::SetCirculationRate($rate)
CoolingSystem::OpenValve($valveNumber)
CoolingSystem::CloseValve($valveNumber)

Thanks to a short expressive interface that forms a coherent abstraction, we can work with the reactor cooling system without having the slightest idea about the low-level implementation details that are characteristic of the selected technology. The use of abstractions can significantly reduce the complexity of the developed system. And the fight against complexity is the main technical imperative of development. Here are some more examples of consistent abstractions:

Speed ​​control system:

  • Set speed
  • Get current settings
  • Restore previous speed value
  • Disable system

Coffee grinder:

  • Enable
  • Switch off
  • Set speed
  • Start grinding coffee
  • Stop grinding coffee

Fuel tank:

  • Fill the fuel tank
  • Drain fuel
  • Get fuel tank capacity
  • Get fuel tank status

Lamp:

  • Enable
  • Switch off

When designing the interface of an object, declare public only those methods that the client needs to manage, hiding everything else. As a result, you should get black boxes, the device of which you can forget after the class code has been added. This approach can significantly reduce the complexity of the developed system.

All Articles