0% found this document useful (0 votes)
16 views9 pages

OODPP Notes

The document discusses several object-oriented design principles and patterns including SOLID principles, creational patterns like factory and singleton, and structural patterns like adapter and decorator. It provides details on each including definitions, applications, and code examples.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views9 pages

OODPP Notes

The document discusses several object-oriented design principles and patterns including SOLID principles, creational patterns like factory and singleton, and structural patterns like adapter and decorator. It provides details on each including definitions, applications, and code examples.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

Object Oriented Design Patterns and Principles

SOLID Principles

 S - Single-responsibility Principle
 O- Open-closed Principle
 L - Liskov Substitution Principle
 I - Interface Segregation Principle
 D - Dependency Inversion Principle

Single-responsibility Principle

Robert C. Martin describes it as:


A class should have one, and only one, reason to change.

A Class should have only one reason to change. It means a class should have only one single job. A class should have
responsibility over a single part of the functionality provided by the software and that responsibility should entirely
encapsulated by the class.

This can be apply for class/component/microservice

Example: Java Persistence API (JPA) specification. It has one, and only one, responsibility: Defining a standardized way to
manage data persisted in a relational database by using the object-relational mapping concept.

Open close principle

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

It means, a new functionalities can be added with minimum changes in existing code. Extensions add as a new classes.

One approach is use interfaces to allow different implementations which you can easily substitute without changing the
code that uses them. The interfaces are closed for modifications, and you can provide new implementations to extend
the functionality of your software. The interface itself is closed for modification, and you can easily extend it by
providing a new interface implementation.

The main benefit of this approach is that an interface introduces an additional level of abstraction which enables loose
coupling.

Liskov Substitution Principle

Subtypes must be substitutable for their super types.

If there is a super type called S and there is a reference type of S named s, and there is subtype of S called T and there
is a reference of T named t. If s can be replace with t without having a impact of client code, we are adhering to
Liskov Substitution principle.
The principle defines that objects of a superclass shall be replaceable with objects of its subclasses without breaking the
application. That requires the objects of your subclasses to behave in the same way as the objects of your superclass.

How to archive LSP:

 An overridden method of a subclass needs to accept the same input parameter values as the method of
the superclass. That means you can implement less restrictive validation rules, but you are not allowed
to enforce stricter ones in your subclass.
 Similar rules apply to the return value of the method. The return value of a method of the subclass
needs to comply with the same rules as the return value of the method of the superclass. You can only
decide to apply even stricter rules by returning a specific subclass of the defined return value, or by
returning a subset of the valid return values of the superclass.

Violation of LSP:

 If we depends on specific sub type inside the client code, we are violating LSP. Example if we depends of
<Supertype> instanceOf <Subtype>

Interface Segregation Principle

Robert C. Martin describes it as:


Clients should not be forced to depend upon interfaces that they do not use.

Many client specific interfaces are better that one general purpose interface, big interfaces should broke down in to
smaller interface.

Goal: reduce the side effects and frequency of required changes by splitting the software into multiple, independent
parts.

Dependency Inversion Principle

Robert C. Martin’s definition of the Dependency Inversion Principle consists of two parts:

1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
2. Abstractions should not depend on details. Details should depend on abstractions.

Depended upon abstraction not concretions.

High-level modules, which provide complex logic, should be easily reusable and unaffected by changes in low-level
modules, which provide utility features. To achieve that, you need to introduce an abstraction that decouples the high-
level and low-level modules from each other.

An important detail of this definition is, that high-level and low-level modules depend on the abstraction. The design
principle does not just change the direction of the dependency, as you might have expected when you read its name for
the first time. It splits the dependency between the high-level and low-level modules by introducing an abstraction
between them. So in the end, you get two dependencies:

1. The high-level module depends on the abstraction, and


2. The low-level depends on the same abstraction.
If you consequently apply the Open/Closed Principle and the Liskov Substitution Principle to your code, it will also follow
the Dependency Inversion Principle.

The Open/Closed Principle required a software component to be open for extension, but closed for modification. You can
achieve that by introducing interfaces for which you can provide different implementations. The interface itself is closed
for modification, and you can easily extend it by providing a new interface implementation.

Your implementations should follow the Liskov Substitution Principle so that you can replace them with other
implementations of the same interface without breaking your application.

Cohesion and Coupling

Low cohesion – functionalities of a module are independent of each other (less re usability, low readability, less
testability)

High cohesion – functionalities of a module are strongly related. (More re usability, more readability, less
testability)[Better]

Coupling- depended of the module on other module

Tight coupled – A module has many relationship with many other modules (interconnections)

Loosely coupled – A module has fewer relationship with other module. [Better]

GRASP (object-oriented design)

https://en.wikipedia.org/wiki/GRASP_(object-oriented_design)
Design Patterns

Creational Design Patterns

 Factory Pattern
 Abstract Factory Pattern
 Singleton

Structural Design Patterns

 Adapter
 Decorator
 Proxy

Behavioral Design Patterns

 Mediator
 Visitor
 Strategy
 Observer

Factory Pattern

Factory Pattern is a creational design pattern that provides an interface for creating objects in a superclass, but allows
subclasses to alter the type of objects that will be created.

IF we have base type and more sub types, depending on a condition we have to select one sub type always use factory
class and choose type depending on a conditions that we passed!
Application

Use the Factory Method when you don’t know beforehand the exact types and dependencies of the objects your code
should work with.

Use the Factory Method when you want to provide users of your library or framework with a way to extend its internal
components.

Abstract Factory Pattern

Abstract Factory patterns work around a super-factory which creates other factories. This factory is also called as factory
of factories.

One level further than factory pattern (factory of factories)


Singleton Pattern
Singleton is a creational design pattern that lets you ensure that a class has only one instance, while providing a global
access point to this instance.

Application:

1. Single database object shared by different parts of the program.


2. Use the Singleton pattern when you need stricter control over global variables.

Singleton code: (single –threaded)

1. private static Singleton instance;

2. private Singleton(){} //private constructor block object initialization

3. public static Singleton getInstance() {


if (instance == null) {
instance = new Singleton(); //work in lazy manner
}
return instance;
}
Singleton code: (Multi –threaded)

 Use eagerly created instance rather than lazy created ones

private static Singleton instance = new Singleton();

public static Singleton getInstance() {


return instance;
}

Here JVM creates the instance of the Singleton when class is loaded JVM creates that instance before any thread
access the static instance variable.

 Use synchronization

public static synchronized Singleton getInstance() {


if (instance == null) {
instance = new Singleton(); }
return instance;
}

Using synchronized key word is bog overhead to the application. It may decrease the performance by 100 times. Here the
problem is only first time synchronization is needed. Therefore it will occurs totally unneeded overhead to application.
The solution is use double check locking in Java

 Use synchronization with double check lock

public static Singleton getInstance() {


if (instance == null) {
synchronized(Singleton.claass){
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}

This can drastically reduce overhead of the application


**Note that: Double check locking java doesn’t work as expected (JVM problem)
Adapter Pattern

Adapter is a structural design pattern that allows objects with incompatible interfaces to collaborate.

Applications:

1. Use the Adapter class when you want to use some existing class, but its interface isn’t compatible with the rest
of your code.
2. Use the pattern when you want to reuse several existing subclasses that lack some common functionality that
can’t be added to the superclass.

Decorator Pattern

Decorator pattern allows a user to add new functionality to an existing object without altering its structure. This type of
design pattern comes under structural pattern as this pattern acts as a wrapper to existing class. This pattern creates a
decorator class which wraps the original class and provides additional functionality keeping class methods signature
intact.

Example from java:

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

InputStreame wrapped using InputStreamReader and it is wrapped using BufferedReader to get more functionalities
from java Input Streams.

You can add chain of functionalities to one particular base object.

Applications

1. Use the Decorator pattern when you need to be able to assign extra behaviors to objects at runtime without
breaking the code that uses these objects.
2. Use the pattern when it’s awkward or not possible to extend an object’s behavior using inheritance. (Inheritance
is static. You can’t alter the behavior of an existing object at runtime. You can only replace the whole object with
another one that’s created from a different subclass.)
Observer Pattern

Observer pattern is used when there is one-to-many relationship between objects such as if one object is modified, its
dependent objects are to be notified automatically. Observer pattern falls under behavioral pattern category.

Publisher + Subscriber pattern. Publisher ->subject, subscriber -> observer. Subject notify all the observers when object
modified.

 Java uses observer patterns in ActionListner and TImerTask classes

Mediator Pattern
Mediator pattern is used to reduce communication complexity between multiple objects or classes. This pattern
provides a mediator class which normally handles all the communications between different classes and supports easy
maintenance of the code by loose coupling.

Mediator & Observer:

The Observer pattern: Defines a one-to-many dependency between objects so that when one object changes state, all
its dependents are notified and updated automatically.

The Mediator pattern: Define an object that encapsulates how a set of objects interact. Mediator promotes loose
coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.

You might also like