In the previous article we have talked about some general suggestions for programming using the object-oriented paradigm. It is imperative to make your code easily modifiable, robust and modularized. This enables reuse and, especially ragarding large projects, easier team work. We have mentioned design patterns - a set of rules and suggestions which help the programmer write well organized code. Now we will discuss different groups of design patterns, and give examples for some of them.
We have learned last time that, most commonly, design patterns are grouped like this: creational, structural, behavioral and concurrency patterns. Let's see the classification of some common design patterns:
- Creational patterns
- Abstract factory
- Lazy initialization
- Object pool
- Structural patterns
- Behavioral patterns
- Chain of responsibility
- Null object
- Single responsibility principle
- Liskov substitution principle
- Concurrency patterns
- Thread pool
Now, let's talk about some of the most commonly used patterns mentioned above. The object pool pattern is a creational design pattern that uses a set of initialized objects kept ready to use - a "pool" - rather than allocating and destroying them on demand. A client of the pool will request an object from the pool and perform operations on the returned object. When the client has finished, it returns the object to the pool rather than destroying it; this can be done manually or automatically. In some situations this approach significantly improves performance, but care is required with implementation, because the object lifetime is slightly more complicated then in a regularly created object.
Another creational pattern, the singleton pattern, restricts the instantiation of a class to only one object. This can be useful when only one object is neeeded to perform administrative or coordination tasks. This pattern can be implemented by declaring all constructors of the class to be private, or providing a static method that returns a reference to the instance.
Proceeding to structural patterns, the bridge pattern is a design pattern used in software engineering which is meant to "decouple an abstraction from its implementation so that the two can vary independently". The bridge uses encapsulation, aggregation, and can use inheritance to separate responsibilities into different classes.
Among the largest group - the behavioral patterns - one of the most interesting patterns is the single responsibility principle. The single responsibility principle revolves around the claim that a certain code module (most often, a class) should only have responsibility over one part of the functionality provided by the software. In software engineering books, this is sometimes also defined like this: the module should only have one reason to change. This means that a division of concerns is performed in the program, and the methods for every concern should be completely encapsulated by a single class.
The Liskov substitution principle states the following: "in a computer program, if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S may substitute objects of type T) without altering any of the desirable properties of that program (correctness, task performed, etc.)". Simply said, any object of some class in an object-oriented program can be replaced by an object of a child class.
Finally, we will say something about the, probably, most important concept in concurrent programming - locking. In computer science, a lock or mutex (from mutual exclusion) is a synchronization mechanism for enforcing limits on access to a resource in an environment where there are many threads of execution. A lock is designed to enforce a mutual exclusion concurrency control policy. Locks prevent multiple threads from accessing a shared variable, and changing its value in such a way that the correctness is compromised. There are many different implementations of locks, including mutexes and semaphores.