Object-Oriented Design
There are three type of objects:
Entity Object or Model Object These objects are usually the data model.
Control Object Control objects are responsible for the coordination of other objects. These are objects that control and make use of other objects.
Boundary Object These boundary objects are responsible for translating information into and out of our system. In an example where we take User commands, we would need the boundary object to translate a keyboard input (like a spacebar) into a recognizable domain event (such as a character jump).
Key Design Principles
Abstraction
Abstraction is the idea of simplifying a concept to its bare essentials in some context. It allows you to better understand the concept by stripping it down to a simplified version.
Encapsulation
Encapsulation black-boxes inner logic and makes your classes easier to manage, because you know what part is used by other systems and what isn’t. This means that you can easily rework the inner logic while retaining the public parts and be sure that you have not broken anything.
In most languages, this is done through the so-called access modifiers (private, protected, and so on).
Decomposition Decomposition is the action of splitting an object into multiple separate smaller parts. Said parts are easier to understand, maintain and program.
There are three types of decomposition relationships:
association — Defines a loose relationship between two components. Both components do not depend on one another but may work together.
aggregation — Defines a weak “has-a” relationship between a whole and its parts. Considered weak, because the parts can exist without the whole.
composition — A strong “has-a” relationship where the whole and the part cannot exist without each other. The parts cannot be shared, as the whole depends on those exact parts.
Generalization
Generalization might be the most important design principle — it is the process of extracting shared characteristics and combining them in one place. All of us know about the concept of functions and class inheritance —both are a kind of generalization.
A comparison might clear things up: while abstraction reduces complexity by hiding unnecessary detail, generalization reduces complexity by replacing multiple entities which perform similar functions with a single construct.
Composition
Composition is the principle of combining multiple objects into a more complex one. Practically said — it is creating instances of objects and using their functionality instead of directly inheriting it.
Cohesion, Coupling & Separation of Concerns
Cohesion
If your class performs one task and nothing else, or has a clear purpose — that class has high cohesion. On the other hand, if it is somewhat unclear in what it’s doing or has more than one purpose — it has low cohesion.
You want your classes to have high cohesion. They should have only one responsibility and if you catch them having more — it might be time to split it.
Coupling
Coupling captures the complexity between connecting different classes. You want your classes to have as little and as simple connections to other classes as possible, so that you can swap them out in future events (like changing web frameworks). The goal is to have loose coupling.
In many languages this is achieved by heavy use of interfaces —they abstract away the specific class handling the logic (using protocol) and represent a sort of adapter layer in which any class can plug itself in.
Separation of Concerns
Separation of Concerns (SoC) is the idea that a software system must be split into parts that do not overlap in functionality.
Benifit
These principles ensure our system is more: - Extendable: High cohesion makes it easier to implement new modules without concern of unrelated functionality. Low coupling means that a new module has less stuff to connect to therefore it is easier to implement.
Maintainable: Low coupling ensures a change in one module will generally not affect others. High cohesion ensures a change in system requirements will require modifying as little number of classes as possible.
Reusable: High cohesion ensures a module’s functionality is complete and well-defined. Low coupling makes the module less dependent on the rest of the system, making it easier to reuse in other software.