Aoop Co1 Notes
Aoop Co1 Notes
Design Patterns
Design patterns in Java are communicating objects and classes that are customized to solve a general
design problem in a particular context. Software design patterns are general, reusable solutions to
common problems that arise during the design and development of software. They represent best
practices for solving certain types of problems and provide a way for developers to communicate about
effective design solutions.
A design pattern is a generic repeatable solution to a frequently occurring problem in software design that
is used in software engineering. It isn’t a complete design that can be written in code right away. It is a
description or model for problem-solving that may be applied in a variety of contexts.
SOLID Principles:
➔ These principles provide the foundation for the effective software design and serves as guidelines
when applying the design patterns.
2. Maintainability: By organizing code into well-known patterns, the codebase becomes easier to
maintain, as the structure is familiar and logical.
3. Flexibility & Extensibility: Design patterns promote a flexible and extensible architecture, making
it easier to adapt to changing requirements and extend the system with new features.
4. Communication & Collaboration: Using design patterns facilitates better communication and
collaboration among developers, as they provide a common vocabulary and understanding.
5. Performance & Effectiveness: Design patterns can lead to more efficient and effective solutions
by leveraging best practices that optimize performance.
6. Best Practice & Standardization: Design patterns embody industry best practices and contribute
to the standardization of design approaches, ensuring consistency across projects.
1. Complexity: Implementing design patterns can add unnecessary complexity to your code,
especially for small or simple projects where a straightforward solution would suffice.
2. Over-Engineering: Using design patterns where they are not needed can lead to over-engineering,
making the codebase harder to understand and maintain.
3. Learning Curve: Understanding and applying design patterns correctly requires time and effort,
which can be challenging for developers who are new to these concepts.
4. Performance Impact: Some design patterns introduce additional layers of abstraction, which can
negatively affect the performance of an application.
5. Code Maintenance: Excessive or inappropriate use of design patterns can lead to a codebase that
is difficult to maintain, as the patterns might obscure the original intent of the code.
6. Development Overhead: Incorporating design patterns can increase development time and effort,
as they often require additional design and implementation steps.
Point to be noted:
The code screenshots included in the document are for reference. These codes have already
been framed as questions, with answers provided in the group. Never attempt to memorize
the code. Focus on understanding the concepts.
➢ Creational Design Patterns
Creational design patterns are a subset of design patterns in software development. They deal with the
process of object creation, trying to make it more flexible and efficient. It makes the system independent
and how its objects are created, composed, and represented.
1. SINGLETON PATTERN
2. FACTORY DESIGN PATTERN
3. ABSTRACT FACTORY PATTERN
4. PROTOTYPE PATTERN
5. BUILDER PATTERN
We will mainly focus on the first three patterns as outlined in your academic
handout.
Singleton Pattern:
➔ Singleton Method is a creational design pattern, it provides a class has only one instance, and that
instance provides a global point of access to it.
In Object Oriented Programming, a java singleton class is a class that can have only one object (an instance
of the class) at a time. After the first time, if we try to instantiate the Java Singleton classes, the new variable
also points to the first instance created. So whatever modifications we do to any variable inside the class
through any instance, affects the variable of the single instance created and is visible if we access that
variable through any variable of that class type defined.
Remember the key points while defining a class as a singleton class that is while designing a singleton
class:
✓ The primary purpose of a java Singleton class is to restrict the limit of the number of object creations
to only one. This often ensures that there is access control to resources, for example, socket or
database connection.
✓ Memory space wastage does not occur with the use of the singleton class because it restricts
instance creation. As the object creation will take place only once instead of creating it each time
a new request is made.
✓ We can use this single object repeatedly as per the requirements. This is the reason why multi-
threaded and database applications mostly make use of the Singleton pattern in Java for caching,
logging, thread pooling, configuration settings, and much more.
Ans:
To create a singleton class, we must follow the steps, given below:
The other difference is that a normal class vanishes at the end of the lifecycle of the application while the
singleton class does not destroy with the completion of an application.
Here, we will see an implementation program for the Singleton class pattern.
Kindly read the comments displayed in the screenshots below for a better understanding of the code.
Factory Design Pattern:
It is a creational design pattern that talks about the creation of an object. The factory design pattern says
to define an interface ( A java interface or an abstract class) for creating the object and let the subclasses
decide which class to instantiate.
What is the Factory Method Design Pattern in Java?
Factory Method Design Pattern define an interface for creating an object, but let subclass decide which
class to instantiate. Factory Method lets a class defer instantiation to subclass.
• Classes delegate responsibility to one of multiple helper subclasses, and you aim to keep the
information about which helper subclass is the delegate within a specific scope or location.
Here, we will see an implementation program for the Factory Design pattern.
Kindly read the comments displayed in the screenshots below for a better understanding of the code.
Below I will enclose with the class diagram (with a real time picture design) you can go through it.
Class Diagram for the above Factory Design Pattern:
Abstract Factory Design Pattern:
The Abstract Factory Pattern is a creational design pattern that provides an interface for creating families
of related or dependent objects without specifying their concrete classes, in simpler terms the Abstract
Factory Pattern is a way of organizing how you create groups of things that are related to each other.
• Abstract Factory pattern is almost similar to Factory Pattern and is considered as another layer of
abstraction over factory pattern.
• Abstract Factory patterns work around a super-factory which creates other factories.
• Abstract factory pattern implementation provides us with a framework that allows us to create
objects that follow a general pattern.
• So at runtime, the abstract factory is coupled with any desired concrete factory which can create
objects of the desired type.
Abstract Factory serves as a high-level blueprint that defines a set of rules for creating families of related
objects without specifying their concrete classes. It declares a series of methods, each responsible for
creating a particular type of object and ensures that concrete factories adhere to a common interface,
providing a consistent way to produce related sets of objects.
2. Concrete Factories
Concrete Factories implement the rules specified by the abstract factory. It contain the logic for creating
specific instances of objects within a family. Also multiple concrete factories can exist, each tailored to
produce a distinct family of related objects.
3. Abstract Products
Abstract Products represents a family of related objects by defining a set of common methods or
properties. It acts as an abstract or interface type that all concrete products within a family must adhere to
and provides a unified way for concrete products to be used interchangeably.
4. Concrete Products
They are the actual instances of objects created by concrete factories. They implement the methods
declared in the abstract products, ensuring consistency within a family and belong to a specific category
or family of related objects.
5. Client
Client utilizes the abstract factory to create families of objects without specifying their concrete types and
interacts with objects through abstract interfaces provided by abstract products. Client enjoys the
flexibility of seamlessly switching between families of objects by changing the concrete factory instan.
This pattern is particularly useful when the client doesn’t know exactly what type to create.
• Isolation of concrete classes:
o The Abstract Factory pattern helps you control the classes of objects that an application
creates.
o Because a factory encapsulates the responsibility and the process of creating product
objects, it isolates clients from implementation classes.
o Clients manipulate instances through their abstract interfaces. Product class names are
isolated in the implementation of the concrete factory; they do not appear in client code.
• Exchanging Product Families easily:
o The class of a concrete factory appears only once in an application, that is where it’s
instantiated.
o This makes it easy to change the concrete factory an application uses.
o It can use various product configurations simply by changing the concrete factory.
o Because an abstract factory creates a complete family of products, the whole product
family changes at once.
o You might need to modify not just the concrete factories but also the abstract factory
interface, potentially impacting existing code.
• Increased Number of Classes:
o As you introduce more abstract factories and product families, the number of classes in
your system can grow rapidly.
o This can make the code harder to manage and understand, particularly for smaller projects.
o In some cases, the Abstract Factory pattern may lead to a violation of the Dependency
Inversion Principle, especially if client code directly depends on concrete factory
implementations rather than the abstract interfaces.
• Limited Extensibility:
o Extending the abstract factory hierarchy or introducing new product families might require
modifications to multiple parts of the code, potentially leading to cascading changes and
making the system less extensible.
• Multiple families of related products: When your system needs to be configured with multiple
families of related products, and you want to ensure that the products from one family are
compatible with the products from another family.
• Flexibility and extensibility: If you need to allow for variations or extensions in the products or their
families, the Abstract Factory pattern provides a way to introduce new product variants without
modifying existing client code.
• Encapsulation of creation logic: The pattern encapsulates the creation of objects, making it
easier to change or extend the creation process without affecting the client code.
• Consistency across product families: If you want to enforce consistency among the products
created by different factories, the Abstract Factory pattern can help maintain a uniform interface.
When not to use Abstract Factory Pattern
• The product families are not likely to change: If the products and their families are unlikely to
change or be extended, using the Abstract Factory pattern might introduce unnecessary
complexity.
• Not dealing with multiple families of objects: If your application is not concerned with creating
families of related objects and you are dealing with single, independent objects, using the Abstract
Factory pattern may be overkill.
• The overhead is too high: In some cases, the overhead of creating and maintaining multiple
factories may outweigh the benefits, especially in smaller applications or when there is no need for
extensive configurability.
• A simpler solution is sufficient: If a simpler creational pattern, such as the Factory Method or
Builder pattern, meets your requirements, there may be no need to introduce the additional
complexity of the Abstract Factory pattern.
Here, we will see an implementation program for the Abstract Factory class pattern.
Kindly read the comments displayed in the screenshots below for a better understanding of the code.
➢ Structural Design Patterns
Structural design patterns are a subset of design patterns in software development that focus on the
composition of classes or objects to form larger, more complex structures. They help in organizing and
managing relationships between objects to achieve greater flexibility, reusability, and maintainability in a
software system.
We will mainly focus on the first three patterns as outlined in your academic
handout.
Adapter Design Pattern:
The Adapter design pattern is a structural design pattern that allows the interface of an existing class to be
used as another interface. It acts as a bridge between two incompatible interfaces, making them work
together. This pattern involves a single class, known as the adapter, which is responsible for joining
functionalities of independent or incompatible interfaces.
Let’s say you have two friends, one who speaks only English and another who speaks only French. You want
them to communicate, but there’s a language barrier.
• You act as an adapter, translating messages between them. Your role allows the English speaker to
convey messages to you, and you convert those messages into French for the other person.
• In this way, despite the language difference, your adaptation enables smooth communication
between your friends.
• This role you play is similar to the Adapter design pattern, bridging the gap between incompatible
interfaces.
Components of Adapter Design Pattern in Java
1. Target Interface:
• Description: Defines the interface expected by the client. It represents the set of operations that
the client code can use.
• Role: It’s the common interface that the client code interacts with.
2. Adaptee:
• Description: The existing class or system with an incompatible interface that needs to be
integrated into the new system.
• Role: It’s the class or system that the client code cannot directly use due to interface mismatches.
3. Adapter:
• Description: A class that implements the target interface and internally uses an instance of the
adaptee to make it compatible with the target interface.
• Role: It acts as a bridge, adapting the interface of the adaptee to match the target interface.
4. Client:
• Description: The code that uses the target interface to interact with objects. It remains unaware of
the specific implementation details of the adaptee and the adapter.
• Role: It’s the code that benefits from the integration of the adaptee into the system through the
adapter.
Here, we will see an implementation program for the Adapter Design pattern.
Kindly read the comments displayed in the screenshots below for a better understanding of the code.
2. Bridge Design Pattern:
The Bridge design pattern allows you to separate the abstraction from the implementation. It is a structural
design pattern.
2. Implementation
This is a design mechanism that encapsulates an implementation class inside of an interface class.
• The bridge pattern allows the Abstraction and the Implementation to be developed independently
and the client code can access only the Abstraction part without being concerned about the
Implementation part.
• The abstraction is an interface or abstract class and the implementer is also an interface or abstract
class.
• The abstraction contains a reference to the implementer. Children of the abstraction are referred
to as refined abstractions, and children of the implementer are concrete implementers. Since we
can change the reference to the implementer in the abstraction, we are able to change the
abstraction’s implementer at run-time. Changes to the implementer do not affect client code.
• It increases the loose coupling between class abstraction and it’s implementation.
UML Diagram of Bridge Design Pattern:
• Refined Abstraction – Extends the abstraction takes the finer detail one level below. Hides the finer
elements from implementers.
• Implementer – It defines the interface for implementation classes. This interface does not need to
correspond directly to the abstraction interface and can be very different. Abstraction imp provides
an implementation in terms of operations provided by the Implementer interface.
Here, we will see an implementation program for the Bridge Design pattern.
Kindly read the comments displayed in the screenshots below for a better understanding of the code.
➢ Decorator Design Pattern
The Decorator Design Pattern is structural design pattern that allows behavior to be added to individual
objects dynamically, without affecting the behavior of other objects from the same class. It involves
creating a set of decorator classes that are used to wrap concrete components.
What is the Decorator Method Design Pattern in Java?
The Decorator design pattern is a structural pattern used in object-oriented programming to add new
functionality to objects dynamically without altering their structure. In Java, this pattern is often employed
to extend the behavior of objects in a flexible and reusable way.
Below are the characteristics of the decorator method design pattern in Java:
• This pattern promotes flexibility and extensibility in software systems by allowing developers to
compose objects with different combinations of functionalities at runtime.
• It follows the open/closed principle, as new decorators can be added without modifying existing
code, making it a powerful tool for building modular and customizable software components.
• The Decorator Pattern is commonly used in scenarios where a variety of optional features or
behaviors need to be added to objects in a flexible and reusable manner, such as in text formatting,
graphical user interfaces, or customization of products like coffee or ice cream.
• Component Interface: An interface or abstract class that defines the core functionality. This is the
base type for both concrete components and decorators.
• Concrete Component: A class that implements the Component interface and provides the basic
behavior.
• Decorator: An abstract class that implements the Component interface and has a reference to a
component object. This class defines the interface for the decorators and includes a reference to a
component instance.
• Concrete Decorators: Classes that extend the Decorator class and add additional behavior to the
Component.
Below is the problem statement to understand decorator method design pattern in Java:
Imagine a pizza shop where customers can customize their pizzas with various toppings like cheese,
pepperoni, mushrooms, and olives. The goal is to create a flexible system that allows you to dynamically
add any combination of toppings to a base pizza without modifying the existing pizza classes or creating
numerous subclasses.
• The Decorator pattern helps solve this problem by allowing you to extend the behavior of a base
pizza object dynamically.
• You can create decorators for each topping, which will add its specific functionality to the base
pizza.
"FOR THE ABOVE DECORATOR PATTERN, THE CLASS DIAGRAM WAS PROVIDED, AND IT WAS FRAMED AS A QUESTION WITH
THE ANSWER ALSO SHARED IN THE GROUP."
Facade Method Design Pattern is a structural design pattern that provides a simplified interface to a
complex subsystem. It acts as a “front door,” concealing the internal complexity of the subsystem and
making it easier for clients to interact with it. In this article, we will get to know about what Facade Method
Design Pattern in Java is, and why we need Facade Method Design Pattern in Java, with the help of a
problem statement and solution.
1. What is the Facade Method Design Pattern in Java?
Facade Design Pattern is a structural design pattern that provides a simplified interface to a set of
interfaces in a subsystem, making it easier to use.
• This simplification helps clients use the subsystem more easily without needing to understand its
complexities.
A BankingFacade could provide simple methods for account creation, transactions, and balance inquiries,
hiding the internal workings of different account types, transaction processing, and security measures.
• Facade Design Pattern is a valuable tool for managing complexity, promoting loose coupling, and
enhancing code readability in Java applications.
• It’s particularly useful when dealing with large, interconnected systems or when you want to create
a simplified interface for external users.
• Facades can control access to certain parts of a subsystem, enhancing security or enforcing usage
patterns.
• It provides a simple, unified interface to a set of interfaces in a subsystem, making it easier to use
and understand.
• Subsystem:
o Represents the complex part of the system that the Facade aims to simplify.
o Comprises multiple classes and interfaces that collaborate to provide a set of
functionalities.
o Clients typically should not interact with the Subsystem directly, but only through the
Facade.
• Facade:
o Clients interact exclusively with the Facade, not with the underlying Subsystem classes.
o Typically has methods that delegate calls to appropriate classes within the
Subsystem, hiding their complexity.
• Client:
o Represents any code that needs to utilize the Subsystem’s functionality.
o Interacts solely with the Facade, unaware of the Subsystem’s internal structure.
o Benefits from the simplified interface provided by the Facade, making code more concise
and maintainable.
Problem Statement:
You are working on a multimedia application that handles various types of media, including audio files,
video files, and image files. The application needs to provide a simple and unified interface for playing audio,
video, and loading images.
• MultimediaFacade class that acts as a single entry point for interacting with the multimedia
subsystem.
• AudioPlayer, VideoPlayer, and ImageLoader, providing a simple playMedia method that takes a
filename and media type as parameters.
• Client code can then use the facade to play different types of media without worrying about the
details of each subsystem component.
"For the above Facade pattern, the class diagram (reference) was provided, and it was framed as a question
with the answer also shared in the group."
We will mainly focus on the first three patterns as outlined in your academic
handout.
Observer Design Pattern is a behavioral design pattern where an object, known as the subject, maintains a
list of its dependents, called observers, that are notified of any changes in the subject’s state. This pattern
is often used to implement distributed event handling systems.
Basically, in Java, the Observer pattern is implemented using the ‘java.util.Observer’ interface and
the ‘java.util.Observable’ class. However, it’s important to note that the Observable class is considered
somewhat outdated, and the ‘java.util’ package doesn’t provide a modern and flexible implementation of
the Observer pattern.
In other words, the Observer Pattern is a behavioral design pattern that defines a one-to-many dependency
between objects so that when one object changes state, all its dependents are notified and updated
automatically. This pattern is commonly used to implement distributed event handling systems.
• Observer: The observer is the interface that defines the update method, which is called by the
subject to notify the observer of a change in the subject’s state.Observers register themselves with
the subject to receive updates.
• Loose Coupling: The Observer Pattern promotes loose coupling between the subject and its
observers. The subject doesn’t need to know the details of its observers, and observers can be
added or removed without affecting the subject.
Here, we will see an implementation program for the Bridge Design pattern.
Kindly read the comments displayed in the screenshots below for a better understanding of the code.
Command Design Pattern:
A Command Pattern says that "encapsulate a request under an object as a command and pass it to invoker
object. Invoker object looks for the appropriate object which can handle this command and pass the
command to the corresponding object and that object executes the command".
It is used:
In chain of responsibility, sender sends a request to a chain of objects. The request can be handled by any
object in the chain.
A Chain of Responsibility Pattern says that just "avoid coupling the sender of a request to its receiver by
giving multiple objects a chance to handle the request". For example, an ATM uses the Chain of
Responsibility design pattern in money giving process.
In other words, we can say that normally each receiver contains reference of another receiver. If one object
cannot handle the request, then it passes the same to the next receiver and so on.
o It allows a set of classes to act as one; events produced in one class can be sent to other handler
classes with the help of composition.
o When more than one object can handle a request and the handler is unknown.
o When the group of objects that can handle the request must be specified in dynamic way.
Here, we will see an implementation program for the Chain of Responsibility Design pattern.
Kindly read the comments displayed in the screenshots below for a better understanding of the code.
➢ Template Design Pattern
Template Design Pattern or Template Method is the behavioral design pattern that defines the skeleton of
an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing
its structure.
This pattern falls under the category of the “behavioral” design patterns as it is concerned with how classes
collaborate and communicate with other classes.
Key Component of Template Method Design Pattern
In Java, the Template Method pattern is implemented using abstract classes. Let’s see the key elements of
the Template Method Pattern:
Abstract Class
• Define an abstract class that declares the template method. The template method typically
consists of a series of method calls and control flow statements.
• The template method defines the algorithm’s structure but leaves some steps to be implemented
by concrete subclasses.
Concrete Classes
• Clients use the template method to execute the algorithm. The template method ensures that the
steps are executed in the correct order, and some steps may be overridden by subclasses.
Hooks
• Hooks are methods in the superclass that have a default (empty or no-op) implementation but can
be optionally overridden by subclasses. They allow subclasses to “hook into” the algorithm at
certain points, influencing its behavior.
So this Pattern provides a way to define the skeleton of an algorithm in the superclass while allowing
subclasses to provide specific implementations for certain steps. This promotes code reuse and ensures
that the overall algorithm structure remains consistent across different implementations.
Here, we will see an implementation program for the Template Design pattern.
Kindly read the comments displayed in the screenshots below for a better understanding of the code.
➢ State Design Pattern:
A State Pattern says that "the class behavior changes based on its state". In State Pattern, we create
objects which represent various states and a context object whose behavior varies as its state object
changes.
The State Pattern is also known as Objects for States.
Benefits:
o It keeps the state-specific behavior.
Usage:
o When the behavior of object depends on its state and it must be able to change its behavior at
runtime according to the new state.
o It is used when the operations have large, multipart conditional statements that depend on the
state of an object.
Here, we will see an implementation program for the Template Design pattern.
Kindly read the comments displayed in the screenshots below for a better understanding of the code.
➢ Strategy Design Pattern
A Strategy Pattern says that "defines a family of functionality, encapsulate each one, and make them
interchangeable".
Benefits:
o It defines each behavior within its own class, eliminating the need for conditional statements.
o It makes it easier to extend and incorporate new behavior without changing the application.
Usage:
o When the multiple classes differ only in their behaviors.e.g. Servlet API.
Here, we will see an implementation program for the Template Design pattern.
Kindly read the comments displayed in the screenshots below for a better understanding of the code.
Remaining Concepts will be continued….
Test Driven development:
❖ TDD is a software development approach in which test cases are developed to specify and
validate what the code will do.
❖ In simple terms, test cases for each functionality are created and tested first and if the test
fails then the new code is written in order to pass the test and making code simple and bug
free.
❖ It starts with designing and developing tests for every small functionality of an application
and instructs developers to write a new code only if an automated test has failed to avoid
duplication.
Junit: Junit is an opensource unit testing framework for JAVA that enables developers to write code
faster with more reliability (consistently good in quality or performance).
Unit Testing:
❖ Unit testing is a way of testing a Unit which refers to the smallest piece of code that is
fetched out of the system.
❖ If tested units are small, the tests tend to run faster providing better insights into the code
and performance.
❖ Unit testing helps in early identification of defects and enables the developers to spend
more time on reading the code rather than developing it.
Manual Testing: Executing testcases manually without any tool. Takes more time and less reliable.
Automated Testing: Executing testcases using a tool automatically. Takes less time and more
reliable.
Junit Features:
Test Suites -> bundles a few unit test cases and runs them together.
Improves code Quality
Automated Test Running
Easy Interpretation -> Uses graphs to show progress
Annotations:
@Test -> Tells Junit which method can be run as a test case.
@Test (time out = 500) -> Sets timeout while executing the test ( To complete test within specified
time).
@Test (expected = IllegalArgumentException.class) -> Uses to handle some exception during the
test execution
@Before -> Methods annotated with the @Before are run before each Test method.
@After -> Methods annotated with the @After are run after each Test method.
@Ignores -> Ignores methods by disabling test methods temporarily.
@BeforeClass -> Executes before all Test methods
Example: test connection must be executed before all the test cases
Assertions:
assertNotEquals(expected, actual) -> Check that two objects are not equal.
assertSame(object1,object2) -> Check whether two objects refer to the same object
assertNotSame(object1,object2) -> Check whether two objects do not refer to the same object
Changes From V4 To V5:
Pros:
❖ Uses Module approach to complete testing without waiting for completion of another part
testing.
❖ Developing team focuses on the provided functionality of the unit and how functionality
should look
❖ Allows to refactor code in future and ensure the module still working without any defect.
Cons:
❖ Can’t test non-functional attributes like usability, scalability, and the overall performance of
the system.
This is the complete notes for the CO1 Advanced Object-Oriented Programming
THANK YOU
BE ONE COMMUNITY