0% found this document useful (0 votes)
78 views82 pages

MCA Course

methode de conception avance cours
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)
78 views82 pages

MCA Course

methode de conception avance cours
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

2 ème Année SC SIW

2023/2024
Course Outline/overview
• Part 1 : Design Pattern (DP)
1. Introduction
2. Creational Patterns
3. Structural Patterns
4. Behavioral Patterns

• Part 2: Model Driven Engineering (MDE)


1. MDA: Principles and Architectures.
2. Meta-modeling languages
3. Model transformation languages.
Course goals
Objective of the first part 'Design Patterns':
• Understand the concept of Design Patterns.
• Distinguish between different types and categories of Design Patterns.
• Apply Design Patterns in real-world contexts.
• Solve specific design problems following the principle of reusability.

The objective of the second part, 'Model-Driven Engineering:


• Describe fundamental knowledge in Model-Driven Engineering.
• Define the principles and architectures of MDE.
• Utilize tools that support MDE."
Prerequisites
• To be able to successfully follow this course, you should have prior
knowledge of:
• Fundamental concepts of modeling.
• Introduction to software engineering.
• Analysis and design of information systems.
• Basic understanding of Object-Oriented Conception and OOP (Object-
Oriented Programming).
software
engineering

UML Modeling

Oop Java
Part 1
Introduction

A 'language' for designing an urban environment.


The units of this language are patterns. They can
indicate the expected window height, the number
of floors in a building, the size of green spaces in a
Patterns in urban planning.
neighborhood."
Introduction
• Pattern: Identify objects that provide a precise solution to a given problem
in a specific context.
• Defining a pattern is providing the why and how of each solution.
• A pattern, or model, is a way of accomplishing something, achieving a
goal, or a technique.
Design Pattern
• What is Gang of Four (GOF)?
• In 1994, four authors Erich Gamma, Richard Helm, Ralph Johnson and John
Vlissides published a book titled Design Patterns - Elements of Reusable Object-
Oriented Software which initiated the concept of Design Pattern in Software
development.
• These authors are collectively known as Gang of Four (GOF). According to
these authors design patterns are primarily based on the following principles of
object oriented design.
• Program to an interface not an implementation.
• Favor object composition over inheritance.
Definition
• Design patterns are typical solutions to common problems in software
design. Each pattern is like a blueprint that you can customize to solve
a particular design problem in your code.
Desgin patterns application
• Factory Method Pattern:
• Application: Java Collections Framework
• Description: The [Link] package includes factory methods like
ArrayList::newInstance and HashMap::newInstance that allow the creation of
collection objects without exposing their concrete implementations.
• Singleton Pattern:
• Application: Database Connection Pooling
• Description: Database connection pools often use the Singleton Pattern to
ensure that a single pool instance is shared across the application, reducing
resource consumption.
• Observer Pattern:
• Application: Event Handling in GUIs (e.g., Java Swing)
• Description: GUI libraries use the Observer Pattern to notify user interface
components (e.g., buttons, checkboxes) of user interactions or changes in
application state.
• Adapter Pattern:
• Application: JDBC (Java Database Connectivity)
• Description: JDBC uses adapters to bridge the gap between the database-specific
drivers and the standardized interface, allowing developers to work with various
databases using a common API.
• Command Pattern:
• Application: Remote Control Systems (e.g., TV remote)
• Description: Remote control systems use the Command Pattern to encapsulate
user requests as objects. These objects can be stored, executed, or undone.
• Composite Pattern:
– Application: Graphic Design Software (e.g., Adobe Illustrator)
– Description: Graphic design applications use the Composite Pattern to
create complex hierarchies of graphical objects, such as layers, groups, and
shapes.
• State Pattern:
– Application: Game Development (e.g., Game AI)
– Description: Game development often employs the State Pattern to manage
the behavior of game characters or AI agents by encapsulating their
different states (e.g., idle, attacking, fleeing).
Usage of Design Pattern
• Design patterns are a toolkit of tried and tested solutions to common problems
in software design. Even if you never encounter these problems, knowing
patterns is still useful because it teaches you how to solve all sorts of problems
using principles of object-oriented design.
• Design patterns define a common language that you and your teammates can
use to communicate more efficiently.
• To accelerate the development process. Providing proven development
paradigms helps save time without the need to reinvent patterns every time a
problem arises. This leads to increased speed and quality of design, which also
reduces costs.
• Design Patterns have a readily understandable and identifiable
architecture for a programmer (improves communication)

• Design Patterns are not really a silver bullet for problems but rather
methods of resolution. It's like a mathematical formula; it is the
solution, but it needs to be applied at the right moment with the right
variables.
Design Pattern representation
• In general, a pattern has four essential elements:
• 1. The pattern name :is a handle we can use to describe a design problem, its
solutions, and consequences in a word or two.
• 2. The problem :describes when to apply the pattern. It explains the problem
and its context. It might describe specific design problems such as how to
represent algorithms as objects.
• 3. The solution describes the elements that make up the design, their
relationships, responsibilities, and collaborations.
• 4. The consequences are the results and trade-offs of applying the pattern.
Though consequences are often unvoiced when we describe design decisions,
they are critical for evaluating design alternatives and for understanding the
costs and benefits of applying the pattern.
Classification
• Design patterns differ by their complexity, level of detail and scale of
applicability. In addition, they can be categorized by their intent and divided
into three groups.
• There are 23 design patterns which can be classified in three categories:
Creational, Structural and Behavioral patterns
Creational • These patterns provide various object
creation mechanisms, which increase
Patterns flexibility and reuse of existing code.

• These patterns explain how to


Structural assemble objects and classes into larger
Patterns structures while keeping these
structures flexible and efficient.

Behavioral • These design patterns are


specifically concerned with
Patterns communication between objects.
Creational Patterns
1. Singleton Pattern
• The Singleton pattern is a design pattern used in software engineering to ensure
that a class has only one instance and provides a global point of access to that
instance.
• It is often used in situations where there should be a single point of control or
coordination, such as managing configuration settings, database connections,
thread pools, and more.
• Authentication and Authorization: Use a Singleton to manage authentication
and authorization tokens or sessions in a web application. This ensures that the
authentication state is consistent across the application.
• Logger: A Singleton logger class can centralize all logging activities in an
application. This allows you to control log levels, formatting, and destinations
(file, console, network) from a single point.
Problem
• The Singleton pattern solves two problems at the same time:
• Ensure that a class has just a single instance. To control how many instances a
class has? The most common reason for this is to control access to some shared
resource—for example, a database or a file.
• Provide a global access point to that instance. Global variables that you used to
store some essential objects? While they’re very handy, they’re also very unsafe
since any code can potentially overwrite the contents of those variables and
crash the app.
• Just like a global variable, the Singleton pattern lets you access some object
from anywhere in the program. However, it also protects that instance from
being overwritten by other code.
Solution
• Make the default constructor private, to prevent other objects from using
the new operator with the Singleton class.
• Create a static creation method that acts as a constructor. Under the hood,
this method calls the private constructor to create an object and saves it in
a static field. All following calls to this method return the cached object.
public class Counter {
public int count=0;
Public void AddOne(){ count++; }
}
public class Programm{
static void Main(){ objA
Counter objA = new Counter(); Count=0

[Link]();} objB
Count=1
}
objA
public class Programm{ Count=1

static void Main(){ Count=2


Counter objB = new Counter();
[Link]();}
}
• To solve this problem, we must first check if there is no instance
in the memory.
• So all users use this only instance (avoid consuming memory
space).
public class Counter { Memory
public int count=0;
Public void AddOne(){ count++; }
}
public class Programm{
static void Main(){
Counter objA = new Counter();
[Link]();}
}
objA
public class Programm{ Count=2

static void Main(){


Counter objB = new Counter();
[Link]();}
}
Structure UML
Singleton
-instance: Singleton
-Singleton ()
Client +getInstance():Singleton
+showMessage()

If (instance==null){
Instance = new Singleton()
}
Return instance
Implementation
public class Singleton {
// create a private variable to store the instance
private static Singleton instance;
// make the constructor private to prevent instantiation
private Singleton(){
Optional Initialization
}
// create a public method to get instance
public static Singleton getInstance() {
//if the instance has not yet been created, create it there
if (instance == null) {
instance = new Singleton();
} return instance; }
public void showMessage() {
[Link](”does something with the singleton instance”); }
}
• How to use this singleton instance (client)

Public class Main{


public static void main(String[] args) {
// Get the single instance of the Singleton
Singleton singletonInstance = [Link]();
// Call methods or access data from the instance
[Link]();
}
}
• Participants
• Singleton
• defines an Instance operation that lets clients access its unique
instance.
• Collaborations
• Clients access a Singleton instance solely through Singleton's
Instance operation.
Consequences
• Controlled Access: The Singleton pattern ensures that there is only one instance of a
class, and it provides a way to access that instance globally. This can be useful when you
want to control and centralize access to a resource or service, ensuring that it's not
abused or duplicated.
• Reduced Memory Footprint: Since there's only one instance of the Singleton class, it can
help reduce the memory footprint of your application by preventing unnecessary
duplication of data.
• Easy to Maintain and Refactor: If you decide to change the implementation of a
Singleton, you only need to modify the Singleton class, and the change will be reflected
throughout the application. This can make your codebase more maintainable and easier
to refactor.
• Permits refinement of operations and representation. The Singleton class may be
subclassed, and it's easy to configure an application with an instance of this extended
class. You can configure the application with an instance of the class you need at run-
time.
2. Builder Pattern
• Builder is a creational design pattern that construct complex objects step by step.
The pattern allows to produce different types and representations of an object
using the same construction code.
• To simplify the construction of complex objects by separating the construction
process from the actual representation of the object.(, so that the same
construction processes can create different representations).
• This pattern is particularly useful when an object has a large number of
optional parameters or configuration options.
• Builder Used in libraries for creating complex objects, such as SQL query
constructors or graphic object constructors.
Problem
• The Builder pattern is typically used in situations where an object has multiple
properties or attributes, some of which may be optional, and it can be difficult
or error-prone to create the object using a constructor with a long list of
parameters or setters for each property. Without the Builder pattern, you might
end up with constructors that have a large number of arguments, making the
code hard to read and maintain.
• Complex object that requires laborious, step-by-step initialization of many fields
and nested objects. Such initialization code is usually buried inside a monstrous
constructor with lots of parameters. Or even worse: scattered all over the client
code.
• Example: create a House object
• To build a simple house, you need to construct four walls and a floor, install a
door, fit a pair of windows, and build a roof.
• A bigger, brighter house, with a swimming pool, garde and other goodies (like
a heating system, plumbing, and electrical wiring)?
1. class House set of subclasses to cover all combinations of parameters.
2. create a giant constructor right in the base House class with all possible
parameters that control the house object (has its downside: not all the
parameters are needed at all times /In most cases most of the parameters will
be unused).
Solution
• The Builder pattern suggests to extract the object construction code out
of its own class and move it to separate objects called builders.
• The Builder pattern lets you construct complex objects step by step. The
Builder doesn’t allow other objects to access the product while it’s
being built.
• Key components of the Builder pattern:
• Product: This is the complex object that you want to create, with multiple
attributes.
• Builder: An interface or abstract class that defines the methods for constructing
the different parts of the product. It typically has methods for setting values for
each attribute and a method for building the final product.
• Concrete Builder: A class that implements the Builder interface. It provides
concrete implementations of the methods for setting attribute values and
building the product.
• Director (optional): An optional component that orchestrates the construction
process. It can guide the order in which the attributes are set, but it's not
always necessary.
UML Structure
Director « interface » Product
Builder
+Builder: Builder
+AddSomething()
+Construct() +Build()

« create »

ConcreteBuilder
Client
+Build()
+GetProduct(): Product
1. The Builder interface declares product construction steps that are
common to all types of builders.
2. Concrete Builders provide different implementations of the construction
steps. Concrete builders may produce products that don’t follow the
common interface.
3. Products are resulting objects. Products constructed by different builders
don’t have to belong to the same class hierarchy or interface.
4. The Director class defines the order in which to call construction steps,
so you can create and reuse specific configurations of products
5. The Client must associate one of the builder objects with the director.
public interface CarBulider {
void setModel(String model);
void setEngine(String engine);
void setColor(String color); public class SportsCarbuilder implements
Car build(); CarBulider{
} private Car car=new Car();

public void setModel(String model) {


[Link](model);
}
public void setEngine(String engine) {
[Link](engine);
}
public void setColor(String color) {
[Link](color);
}
public Car build(){
return car; }
}
// Product
class Car {
private String model;
private String engine;
private String color;

public void setModel(String model) {


[Link] = model;
}
public void setEngine(String engine) {
[Link] = engine;
}
public void setColor(String color) {
[Link] = color;
}
public String toString() {
return "Car [Model: " + model + ", Engine: " + engine + ", Color: " +
color + "]";
}
}
public class CarManufactur {

public Car construct(CarBulider builder) {


[Link]("Sports Car");
[Link]("V8");
[Link]("Red");
return [Link]();
} public class Program {
}
public static void main(String[] args) {
CarBulider builder = new SportsCarbuilder();
CarManufactur manufacturer = new CarManufactur();
Car sportsCar = [Link](builder);

[Link]("Car created: " + sportsCar);


}

// TODO code application logic here


}
Output:
Car created: Car [Model: Sport Car, Engine: V8, Color: Red]
Consequences
• Separation of Concerns: The Builder pattern separates the construction of an
object from its representation. This separation makes the code more
maintainable, as changes to the construction process do not affect the client
code that uses the builder.
• The parameters to the constructor are reduced and are provided in highly
readable method calls.
• Builder design pattern also helps in minimizing the number of parameters in the
constructor and thus there is no need to pass in null for optional parameters to
the constructor.
• The number of lines of code increases at least to double in builder pattern, but
the effort pays off in terms of design flexibility and much more readable code.
• Requires creating a separate ConcreteBuilder for each different type of Product.
Prototype Pattern
• Prototype allows us to hide the complexity of making new instances from the
client.
• The concept is to create new objects by copying an existing object, known as a
prototype, instead of creating them from scratch.
• This approach saves costly resources and time, especially when object creation
is a heavy process.
• Prototype patterns are required, when object creation is time consuming, and
costly operation, so we create objects with the existing object itself.
• One of the best available ways to create an object from existing objects is
the clone() method. Clone is the simplest approach to implement a prototype
pattern. However, it is your call to decide how to copy existing object based on
your business model.
Use of Prototype
• This pattern is used when creation of object directly is costly. For example, an object
is to be created after a costly database operation. We can cache the object, returns its
clone on next request and update the database as and when needed thus reducing
database calls.
• Undo Mechanisms: In applications that support undo/redo functionality, the
Prototype pattern can be used to create and store snapshots (prototypes) of objects
before changes are made. This allows you to revert to previous states easily.
• Game Development: In game development, the Prototype pattern can be used to
create copies of game entities, characters, or items with varying attributes, making it
easier to spawn and manage game objects.
• Document Editors: In document editing applications, where you want to create new
documents based on templates or existing documents, the Prototype pattern can be
used to clone the structure and content of documents.
Problem
• To create an exact copy of an Object,
• Create a new object of the same class. Then you have to go through all the
fields of the original object and copy their values over to the new object.
• Problem: Not all objects can be copied that way because some of the object’s
fields may be private and not visible from outside of the object itself.
• One more problem :Since you have to know the object’s class to create a
duplicate, your code becomes dependent on that class.
• But sometimes you only know the interface that the object follows, but not its
concrete class, when, for example, a parameter in a method accepts any objects
that follow some interface.
Problem
• The Prototype pattern can be applied to various problems and scenarios where
you need to create objects that are similar to existing objects
• Expensive Object Initialization: When creating an object involves complex or
resource-intensive initialization processes, such as database queries, network
requests, or file I/O. Cloning an existing object can save time and resources.
• Configurable Object Creation: When you have objects with numerous
configuration options or parameters, and you want to create new objects with
similar configurations, but with minor differences. You can create a prototype
with a base configuration and clone it, making adjustments as needed.
Solution
• The Prototype pattern delegates the cloning process to the actual objects that
are being cloned. The pattern declares a common interface for all objects that
support cloning. This interface lets you clone an object without coupling your
code to the class of that object. Usually, such an interface contains just a
single clone method.

• The implementation of the clone method is very similar in all classes. The
method creates an object of the current class and carries over all of the field
values of the old object into the new one. You can even copy private fields
because most programming languages let objects access private fields of other
objects that belong to the same class.
Example
• Let's suppose we have a word processing system in which users can
create various types of documents, such as letters, reports, or contracts.
Each of these documents can have a basic format with predefined
headers, footers, and text styles. The user wants to be able to create
new documents using these basic templates and then customize the
content and styles according to their needs.
Solution using the Prototype Pattern
• Prototype Creation: Firstly, we create prototypes for each type of document (letter
report, contract). Each prototype serves as a pre-filled example of its document
type, featuring predefined headers, footers, and text styles.
• Prototyping: When a user wishes to create a new document, the system prompts
the corresponding prototype to clone itself. For instance, if the user wants to
create a new letter, the system utilizes the letter prototype to make a copy.
• Document Customization: Once the copy of the prototype is created, the user can
personalize the content by adding their own text, modifying headers and footers,
or altering text styles.
• Using the Customized Document: When the user has finished customizing, the
personalized document is used like any other document. It can be saved, printed,
or shared.
UML Structure
« Inteface »
Prototype

Client
+clone():Prototype

ConcretePrototype

+ConcretePrtotype(prototype)
+clone():Prototype
uses
SubclassPrototype

+SubclassPrtotype(prototype)
+clone():Prototype
public class Human implements Prototype{
public interface Prototype { private String name;
private String lastName;
public Prototype getClone(); private int age;

} public Human(){
[Link](" Human description ");
Prototype Class [Link]("---------------------------------");
[Link]("Name"+"\t"+"Last Name"+"\t"+"Age");
}
public Human(String name, String lastName, int age) {
this();
[Link] = name;
[Link] = lastName;
[Link] = age;
showHuman();
}
private void showHuman(){
[Link](name+"\t"+lastName+"\t"+age);
}
@Override
public Prototype getClone() {
Human Class
return new Human(name, lastName, age);
}
}
public class HumanPrototypeMain extends Human {

public static void main(String[] args) {

Human human1 = new Human("Erwan", "Le Tutour", 30);

Human human2 = (Human) [Link]();


}
}

HumanPrototypeMain Class
• First we need to create our prototype class
• The getClone() method will be implemented in the class that will
implement the prototype to return a new object of the same class.
In the next example we will create a Human and then implement the
method to clone him.
• the getClone() will return another Human with the same name, last
name and age to the one created before.
• my human2 has the same properties values as my human1, but they will
only be equals if I implement the equals() method to do so.
Consequences
• Specifying new objects by varying values – Highly dynamic systems let you
define new behavior through object composition by specifying values for an
object’s variables and not by defining new classes. For example, you could have
a basic object "Shape" with variables such as color, size, position, etc.
Depending on the values you assign to these variables, you can create different
shapes and behaviors.
• Specifying new objects by varying structure – Many applications build objects
from parts and subparts. For convenience, such applications often let you
instantiate complex, user-defined structures to use a specific subcircuit again
and again. for example, a graphic application that creates drawings from
geometric shapes)
• instead of creating a new class for each type of drawing, you can have a library
of generic structures that represent different combinations of geometric shapes.
You can then instantiate these structures, modify them if necessary and use
them to create specific drawings.

• It reduces the need of sub-classing.


• It hides complexities of creating objects.
• The clients can get new objects without knowing which type of object it will be.
• It lets you add or remove objects at runtime.
1. The Prototype interface declares the cloning methods. In most cases, it’s a
single clone method.
2. The Concrete Prototype class implements the cloning method. In addition
to copying the original object’s data to the clone, this method may also
handle some edge cases of the cloning process related to cloning linked
objects, untangling recursive dependencies, etc.
3. SubclassPrototype will use this concrete class Concrete Prototype .
4. The Client can produce a copy of any object that follows the prototype
interface.
Factory Method Pattern
• Factory Method 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(let subclasses decide which class to instantiate).
• In Factory pattern, we create object without exposing the creation logic to the
client and refer to newly created object using a common interface.

• Why use the Factory design pattern?


1. Flexibility: Different subclasses can create different types of objects without
altering the client code.
2. Code Maintenance: Changes to object creation logic are isolated within the
respective subclasses, minimizing impact on the rest of the codebase.
Problem
• Creating a logistics management application. The first version of the app can
only handle transportation by trucks, so the bulk of the code lives inside
the Truck class.
• After a while, the app becomes pretty popular. Each day you receive dozens of
requests from sea transportation companies to incorporate sea logistics into the
app.
• Adding a new class to the program isn’t that simple if the rest of the code is
already coupled to existing classes.
• At present, most of the code is coupled to the Truck class. Adding Ships into
the app would require making changes to the entire codebase. Moreover, if later
you decide to add another type of transportation to the app, you will probably
need to make all of these changes again.
Solution
• The Factory Method pattern suggests that you replace direct object construction
calls (using the new operator) with calls to a special factory method. but it’s
being called from within the factory method. Objects returned by a factory
method are often referred to as products.
• Now you can override the factory method in a subclass and change the class of
products being created by the method.
• There’s a slight limitation though: subclasses may return different types of
products only if these products have a common base class or interface. Also, the
factory method in the base class should have its return type declared as this
interface.
Solution
• The code that uses the factory method (often called the client code) doesn’t
see a difference between the actual products returned by various subclasses.
The client treats all the products as abstract Transport. The client knows that
all transport objects are supposed to have the deliver method, but exactly how
it works isn’t important to the client.
Example of the Factory Method
• In a ‘Drawing’ system, depending on the user’s input, different pictures like
squares, rectangles, the circle can be drawn.
• Another example: On the travel site, we can book train tickets as well as bus
tickets and flight tickets. In this case, the user can give his travel type as ‘bus’,
‘train’, or ‘flight’.
• DVD Player:
• These days, DVD players support, DVD, CD, Blue-Ray. All of them are
inserted in the same drive. It is the players DiskFactory’s responsibility to
instantiate the correct Disk object in run-time. So DiskFactory will
instantiate DVDDisk , CDDisk , BlueRayDisk at run-time and output
at IDisk object.
• getInstance() method of [Link], NumberFormat,
and ResourceBundle uses factory method design pattern.
• All the wrapper classes like Integer, Boolean etc uses this pattern to evaluate
the values using the valueOf() method.
UML Structure
Creator « Interface »
….. Product
+someOperation() …..
+createProduct(): Product +doStuff()

ConcreteCreatorA ConcreteCreatorB Concrete Concrete


….. ….. ProductA ProductB
+createProduct(): Product +createProduct(): Product
1. The Product declares the interface, which is common to all objects that can be
produced by the creator and its subclasses.
2. Concrete Products are different implementations of the product interface.
3. The Creator class declares the factory method that returns new product
objects. It’s important that the return type of this method matches the
product interface.
4. Concrete Creators override the base factory method so it returns a different
type of product.
• Note that the factory method doesn’t have to create new instances all the time.
It can also return existing objects from a cache, an object pool, or another
source.
public interface MotorVehicle
{
void build(); public class Motorcycle implements MotorVehicle
} {
@Override
public void build()
{
[Link]("Build Motorcycle");
}
}
public class Car implements MotorVehicle
{
@Override
public void build()
{
[Link]("Build Car");
}
}
public abstract class MotorVehicleFactory
{
public MotorVehicle create()
{
MotorVehicle vehicle = createMotorVehicle();
[Link]();
return vehicle;
}
protected abstract MotorVehicle createMotorVehicle();
}

public class MotorcycleFactory extends MotorVehicleFactory


{
@Override
protected MotorVehicle createMotorVehicle()
{
return new Motorcycle();
}} public class CarFactory extends MotorVehicleFactory
{
@Override
protected MotorVehicle createMotorVehicle()
{
return new Car();
}}
• First, we define the MotorVehicle interface. This interface only has a
method build(). This method is used to build a specific motor vehicle.
• Next, implement the concrete classes that implement
the MotorVehicle interface. We create two types: Motorcycle and Car.
• Then, we create the MotorVehicleFactory class. This class is responsible for
creating every new vehicle instance. It’s an abstract class because it makes a
specific vehicle for its particular factory.
• As you can notice, the method create() calls to the abstract
method createMotorVehicle() to create a specific type of motor vehicle. That’s
why each particular motor vehicle factory must implement its
correct MotorVehicle type. Previously, we implemented
two MotorVehicle types, Motorcycle and Car. Now, we extend from our base
class MotorVehicleFactory to implement both.
• First, the MotorcycleFactory class, Then, the CarFactory class:
Consequences
• You avoid tight coupling between the creator and the concrete products.
• Single Responsibility Principle. You can move the product creation code into
one place in the program, making the code easier to support.
• Open/Closed Principle. You can introduce new types of products into the
program without breaking existing client code.

• The code may become more complicated since you need to introduce a lot of
new subclasses to implement the pattern. The best case scenario is when you’re
introducing the pattern into an existing hierarchy of creator classes.
Abstract Factory Pattern
• Abstract Factory is a creational design pattern that lets you produce families of
related objects without specifying their concrete classes.
• 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.
• This pattern is commonly used when we start using the Factory Method Pattern,
and we need to evolve our system to a more complex system. It centralizes the
product creation code in one place.
Problem
• After the first app iteration, two new vehicle brand companies are interested in
our system: NextGen and FutureVehicle. These new companies build not only
fuel-only vehicles but also electric vehicles. Each company has its vehicle design.
• Our current system is not ready to address these new scenarios. We must
support electric vehicles and consider that each company has its design. To
resolve these problems, we can use the Abstract Factory Pattern.
• A family of related products, say: MotorVehicle , ElectricVehicle .
• Several variants of this family. For example, products MotorVehicle are
available in these variants: NextGen and FutureVehicle. .
• You need a way to create individual objects so that they match other objects of
the same family.
Problem
• Also, you don’t want to change existing code when adding new products or
families of products to the program. Vendors update their catalogs very often,
and you wouldn’t want to change the core code each time it happens.
Solution
• The first thing the Abstract Factory pattern suggests is to explicitly declare
interfaces for each distinct product of the product family (e.g. MotorVehicle ,
ElectricVehicle ). Then you can make all variants of products follow those
interfaces. For example, all MotorVehicle variants can implement the
MotorVehicle interface; all ElectricVehicle variants can implement the
ElectricVehicle interface, and so on.
• Next move is to declare the Abstract Factory—an interface with a list of creation
methods for all products that are part of the product family (for
example, createMotorVehicle,() createElectricVehicle()). These methods must
return abstract product types represented by the interfaces we extracted.
• Now, how about the product variants? For each variant of a product family, we
create a separate factory class based on the AbstractFactory interface. A factory
is a class that returns products of a particular kind. For example,
the NextGenCorporation can only create NextGenMotorcycle and
NextGenElectricCar objects.
• The client code has to work with both factories and products via their
respective abstract interfaces. This lets you change the type of a factory that you
pass to the client code, as well as the product variant that the client code
receives, without breaking the actual client code.
UML Structure
ConcreteFactory1
….. CreateProductA1 CreateProductB1
+createProductA(): ProductA
+createProductB(): ProductB

AbstractFactory
« Interface » « Interface »
…..
ProductA ProductB
+createProductA(): ProductA
+createProductB(): ProductB

CreateProductA2 CreateProductB2
ConcreteFactory2
…..
+createProductA(): ProductA
+createProductB(): ProductB
public interface ElectricVehicle
{
void build();
}
public abstract class Corporation {
public abstract MotorVehicle createMotorVehicle();
public abstract ElectricVehicle createElectricVehicle();
}

public class FutureVehicleMotorcycle implements MotorVehicle {


@Override
public void build() {
[Link]("Future Vehicle Motorcycle");
}
}

public class FutureVehicleElectricCar implements ElectricVehicle {


@Override
public void build() {
[Link]("Future Vehicle Electric Car");
}
}
public class NextGenMotorcycle implements MotorVehicle {
@Override
public void build() {
[Link]("NextGen Motorcycle");
}
}

public class NextGenElectricCar implements ElectricVehicle {


@Override
public void build() {
[Link]("NextGen Electric Car");
}
}
public class FutureVehicleCorporation extends Corporation {
@Override

public MotorVehicle createMotorVehicle() {


return new FutureVehicleMotorcycle();
}
@Override
public ElectricVehicle createElectricVehicle() {
return new FutureVehicleElectricCar();
}
}

public class NextGenCorporation extends Corporation {


@Override

public MotorVehicle createMotorVehicle() {


return new NextGenMotorcycle();
}
@Override public ElectricVehicle createElectricVehicle() {
return new NextGenElectricCar();
}
}
1. We already have the MotorVehicle interface. Additionally, we must add an
interface to represent electric vehicles
2. Next, we create our abstract factory. The new class is abstract because the
responsibility of object creation will be for our concrete factory. This behavior
follows the OCP and SRP. Let’s jump into class definition
3. Before we create the concrete factory for each company, we must implement
some vehicles for our new companies. Let’s make some new classes
for FutureVehicle company.
4. Then, the electric car instance.
5. We do the same for the NexGen company
6. Additionally, the other electric car concrete implementation.
7. Finally, we are ready to build our concrete factories.
First, FutureVehicle factory, Next, the other one.
1. Abstract Products declare interfaces for a set of distinct but related products
which make up a product family.
2. Concrete Products are various implementations of abstract products, grouped
by variants. Each abstract product (chair/sofa) must be implemented in all
given variants (Victorian/Modern).
3. The Abstract Factory interface declares a set of methods for creating each of
the abstract products.
4. Concrete Factories implement creation methods of the abstract factory. Each
concrete factory corresponds to a specific variant of products and creates only
those product variants.
5. Although concrete factories instantiate concrete products, signatures of their
creation methods must return corresponding abstract products. This way the
client code that uses a factory doesn’t get coupled to the specific variant of the
product it gets from a factory. The Client can work with any concrete
factory/product variant, as long as it communicates with their objects via
abstract interfaces.
Consequences
• You can be sure that the products you’re getting from a factory are compatible
with each other.
• You avoid tight coupling between concrete products and client code.
• Single Responsibility Principle. You can extract the product creation code into
one place, making the code easier to support.
• Open/Closed Principle. You can introduce new variants of products without
breaking existing client code.
• The code may become more complicated than it should be, since a lot of new
interfaces and classes are introduced along with the pattern.

You might also like