Object Oriented Design
Object oriented design is a set of principles that make it easier for programs to change. It's essentially about limiting and managing dependencies such that a change to one object has minimal ramifications to other parts of the codebase.
SOLID
Single Responsibility Principle
A class should have one, and only one, reason to change.
If a class has multiple reasons to change/has multiple responsibilities, then a change to one responsibility will have consequences to the unrelated responsibility. This can result in unintended consequences, such as breaking the functionality of a completely different object. If a class only has one reason to change because it has one responsibility, then the effect of the change will be easy to predict and the affected classes will be easy to identify.
Open/Closed Principle
Classes, modules, and functions should be open for extension, but closed for modification.
Prior to the advent of OO languages, it was difficult to add/change the functionality to a software entity without modifying, and thus causing problems in other areas of code. This was solved through inheritance and polymorphism.
Liskov Substitution Principle
A subclass should have the same interfaces as its parent.
A user shouldn't need to know that it is working with a subclass instead of its parent. A method on a subclass should take the same arguments and have the same results as the same method on its parent. A square may be a type of rectangle in the real world, but it should not be one in software. Since squares have the same height and width, it may be tempting to overwrite its parent's set_width and set_height methods to also set the height and width, respectively. But this would cause the interfaces to act differently depending on whether you were working on the child or the parent, and would inevitably result in someone trying to use one like the other.
Interface Segregation Principle
Many client-specific interfaces are better than one general-purpose interface.
Break up classes into roles so that they only implement methods that are always going to be used. This will prevent other objects that use those classes from needing to know and depending on unrelated methods.
Dependency Inversion Principle
Use abstractions to keep high-level modules from having to depend on low-level modules.
Higher level modules shouldn't know how it's lower level modules are implemented. They should be given an interface that abstracts away how it's doing what it's doing, but still be given the power to tell it what to do. Rails, for example, abstracts the process of writing SQL queries to ActiveRecord. Rails models can query databases without knowing how SQL queries work.
Dependency Injection
Dependency injection is a strategy for reducing coupling in code. By passing an object as an argument to the constructor of another object, the receiving object doesn't have to know exactly what the object its getting is, thus different objects can be passed, granting greater flexibility and an inversion of control.
Law of Demeter
Also known as the principle of least knowledge, the Law of Demeter (not an actual law) asserts that an object should assume as little as possible about other objects, including subcomponents. Generally, objects should not call the methods of other objects they're connected to, since this would mean that one object knows the inner workings of of other distant objects. For example user.notifications[0].message.sender.posts would imply that the user object has intimate knowledge of the inner workings of the sender object, and would thus be tightly coupled together.
A m method of object O should only invoke the methods of the methods of the following objects:
Oitselfm's parameters- Any objects create/instantiated within
m O's direct component objects- A global variable, accessible by
O, in the scope ofm