5. Non GoF design patterns
Multiton¶
Definition¶
Multiton pattern ensures there are a predefined amount of instances available globally. It is generalization of Singleton pattern
Usage¶
- There must be a specific number of instances of a class, and they must be accessible to clients from a well-known access point.
Double-checked locking¶
Definition¶
This pattern reduces the number of lock acquisitions by simply checking the locking condition beforehand. As a result of this, there’s usually a performance boost.
public class Singleton {
private Singleton() {}
private static volatile Singleton INSTANCE;
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized (Singleton.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
Usage¶
- If there would be just one check, another thread can create new instance during instance creation actual thread.
- If there would be just two checks, it would be the same like with just one check.
- If there would be check and then lock, you could check for null, then you would try to lock critical part of that code but lock could by acquired at that specific moment so after acquiring the lock, you would overwrite existing instance.
- If you would first lock and then check, it would work but locking it every time is expensive.
Thread pool¶
Definition¶
A Thread Pool is a design pattern which consists of a number N of threads running a number M of jobs concurrently.
Implementation Details¶
The algorithm used to determine when to create or destroy threads affects the overall performance: - Creating too many threads wastes resources and costs time creating the unused threads. - Destroying too many threads requires more time later when creating them again. - Creating threads too slowly might result in poor client performance (long wait times). - Destroying threads too slowly may starve other processes of resources.
Pros and Cons¶
Pros¶
- The number of threads may be dynamically adjusted during the lifetime of an application based on the number of waiting tasks.
Usage¶
- In modern operating systems creating a thread or a process is an expensive operation, so avoiding it in those use-cases will improve the performance of the system as well as guarantee that the system won’t spawn too many processes.
Mock object¶
Definition¶
A Mock Object is an object that substitutes for a real object. In object-oriented programming, mock objects are simulated objects that mimic the behavior of real objects in controlled ways
Pros and Cons¶
Pros¶
- Dependencies are reduced/eliminated.
- Tests will run faster (if, for instance, we do not hit the actual database)
- Once we mock out everything we can, if testing is still difficult this is likely revealing a weakness in design.
Dependency injection¶
Definition¶
Dependency injection is a technique that makes a class independent of its dependencies. It achieves that by decoupling the usage of an object from its creation. This helps you to follow SOLID’s dependency inversion and single responsibility principles.
Implementation Details¶
There are three ways for a class to get an object it needs:
- The class constructs the dependency it needs. In the example above,
Carwould create and initialize its own instance ofEngine. - Grab it from somewhere else. Frameworks and libraries can provide created instances of its classes.
- Have it supplied as a parameter. The app can provide these dependencies when the class is constructed or pass them in to the functions that need each dependency. In the example above, the
Carconstructor would receiveEngineas a parameter. The third option is dependency injection! With this approach you take the dependencies of a class and provide them rather than having the class instance obtain them itself.
There are two major ways to do dependency injection:
- Constructor Injection. This is the way described above. You pass the dependencies of a class to its constructor.
- Field Injection (or Setter Injection). With field injection, dependencies are instantiated after the class is created. The code would look like this:
Pros and Cons¶
Pros¶
- Reusability of classes and decoupling of dependencies: It’s easier to swap out implementations of a dependency. Code reuse is improved because of inversion of control, and classes no longer control how their dependencies are created, but instead work with any configuration.
- Ease of refactoring: The dependencies become a verifiable part of the API surface, so they can be checked at object-creation time or at compile time rather than being hidden as implementation details.
- Ease of testing: A class doesn’t manage its dependencies, so when you’re testing it, you can pass in different implementations to test all of your different cases.
Cons¶
Usage¶
Manual dependency injection also presents several problems:
- For big apps, taking all the dependencies and connecting them correctly can require a large amount of boilerplate code. In a multi-layered architecture, in order to create an object for a top layer, you have to provide all the dependencies of the layers below it.
- When you’re not able to construct dependencies before passing them in There are libraries that solve this problem by automating the process of creating and providing dependencies. They fit into two categories:
- Reflection-based solutions that connect dependencies at runtime.
- Static solutions that generate the code to connect dependencies at compile time.
Lazy loading¶
Definition¶
Lazy loading is the practice of delaying load or initialization of resources or objects until they’re actually needed to improve performance and save system resources. It also aims to reduce unnecessary work in an application that loads objects from a database, while avoiding loading aspects of the object that the application does not use.
Implementation Details¶
- Lazy initialization – This method sets objects to null. Object data is loaded only after and whenever invoking them, check if null, and if so, load object data.
- Virtual proxy – when accessing an object, call a virtual object with same interface as the real object. When the virtual object is called, load the real object, then delegate to it.
- Ghost – load an object in partial state, only using an identifier. The first time a property on the object is called, load the full data.
- Value holder – create a generic object that handles lazy loading behavior. This object should appear in place of an object’s data fields.
Pros and Cons¶
Pros¶
- Reduces initial load time – Lazy loading a webpage reduces page weight, allowing for a quicker page load time. Or loading
- Bandwidth conservation – Lazy loading conserves bandwidth by delivering content to users only if it’s requested.
- System resource conservation – Lazy loading conserves both server and client resources, because only some of the images, JavaScript and other code actually needs to be rendered or executed.
Null object¶
Definition¶
The Null object pattern is a design pattern that simplifies the use of dependencies that can be undefined. This is achieved by using instances of a concrete class that implements a known interface, instead of null references. We create an abstract class specifying various operations to be done, concrete classes extending this class and a null object class providing do nothing implementation of this class and will be used seamlessly where we need to check null value.
Implementation Details¶
- The Null Object class is often implemented as a Singleton. Since a null object usually does not have any state, its state can’t change, so multiple instances are identical. Rather than use multiple identical instances, the system can just use a single instance repeatedly.
Marker interface¶
Definition¶
Marker interface is empty interface, so it doesn’t force user to implement anything. It is used to distinguish special treated object.
package java.io;
public interface Serializable {
}
Implementation Details¶
- Another example in Java is Cloneable
Usage¶
- Use the Marker Interface pattern when you want to identify the special objects from normal objects (to treat them differently) you want to mark that some object is available for certain sort of operations