ASM2 ADVANCE TaMinhAnh. 3
ASM2 ADVANCE TaMinhAnh. 3
Student declaration
I certify that the assignment submission is entirely my own work and I fully understand the consequences of plagiarism. I understand that making a
false declaration is a form of malpractice
Student’s signature Quy
Grading grid
P3 P4 M3 M4 D3 D4
❒ Summative Feedback: ❒ Resubmission Feedback:
s
1. Introduction............................................................................................................................4
2. Scenario analysis....................................................................................................................4
2.1 Scenario.................................................................................................................................4
2.2 Diagram.................................................................................................................................5
3. Implementation......................................................................................................................6
3.1 Code.......................................................................................................................................6
3.2 Program screenshots............................................................................................................25
4. Discussion............................................................................................................................26
4.1 Range of similar patterns.....................................................................................................26
4.2 Usage of pattern...................................................................................................................27
REFERENCES............................................................................................................................30
1. INTRODUCTION
Design patterns are widely recognized as a valuable tool for developing high-quality, reusable
software solutions. By using design patterns, developers can apply proven solutions to common
programming problems and create more maintainable and scalable code. This assignment will
focus on implementing code using design patterns and investigating scenarios in which they can be
applied, as well as discuss a range of design patterns with relevant examples of creational,
structural, and behavioral pattern types. By completing this assignment, I will gain a deeper
understanding of how design patterns can be used to improve software development practices and
produce more efficient and effective code.
2. SENARIO ANALYSIS
2.1 Scenario
Scenario: In the city centre, there is a renowned restaurant named "World Flavors" famous for its
diverse menu that includes dishes from Japan, Italy, and South Korea. The restaurant was founded
by two talented chefs, John and David. Both chefs share a passion for the culinary arts and have
extensive cooking experience, especially in their respective culinary backgrounds.
To efficiently manage the preparation of the restaurant's diverse dishes, John and David have
decided to implement an Abstract Factory Design Pattern. They want to ensure that each dish in
their restaurant is professionally prepared and meets the culinary standards of these three countries.
In this project, they divided the restaurant into three sections: Japanese cuisine, Italian cuisine, and
Korean cuisine. Each area has its own "culinary factory," operating as an Abstract Factory. These
culinary workshops have the task of creating culinary products according to customer requests.
- About Italian cuisine: customers can choose from three Bruschetta options: Classic bruschetta,
Steak and blue cheese bruschetta, and Chicken Salad bruschetta.
- About Japanese cuisine: There's also the option of warm or cold Edamame dishes.
- About Korean cuisine: customers can choose from Cabbage Kimchi, Cucumber Kimchi, and
Mustard Leaf Kimchi.
For the Main Course: For each type of dish, there will be a different function/method of that dish.
- About Italian cuisine, there are pizza options including Cheese Pizza, Veggie Pizza, and Pepperoni
Pizza. Customers can also choose to customize the pizza with extra cheese, extra vegetables, and
extra pepperoni.
- About Japanese cuisine: there are 3 types of Ramen for customers to choose such as Shoyu
Ramen, Miso Ramen, and Shio Ramen. Customers have the freedom to customize their ramen,
choosing from sour, spicy, salty, or sweet options.
- About Korean cuisine: For Tokbokki, they can choose from traditional tokbokki, Spicy Tokbokki,
or Cheese Tokbokki.
For the Desserts: There are Mochi, Tiramisu, and Bingsu. Customers can adjust the sweetness of the
dessert they choose to their liking.
When customers arrive and place their orders, the receptionist will inquire whether they would like
to try Japanese or Italian cuisine. Depending on their choice, the receptionist will guide them to the
corresponding area of the restaurant. Here, the restaurant utilizes the Abstract Factory pattern to
prepare dishes according to the customers' preferences, ensuring that each dish served is a culinary
masterpiece from one of these three nations. The Abstract Factory Design Pattern has helped them
efficiently organize the food preparation process, maintain consistency, and present visually
appealing dishes to the customers.
2.2 Diagram
Explanation:
The class diagram represents an implementation of the Abstract Factory design pattern for a
restaurant management system. The diagram includes interfaces like IRestaurantFactory,
IAppetizer, IMainCourse, and IDessert.
IRestaurantFactory defines methods for creating different types of dishes, and concrete
implementations such as ItalianDishFactory, JapaneseDishFactory, and KoreanDishFactory,
these classes inherit from IRestaurantFactory, implement IRestaurantFactory to provide a
specific way to generate dish types from the respective countries. For example,
ItalianDishFactory makes Bruschetta, Pizza, and Tiramisu.
Abstract Products such as IAppetizer, IMainCourse, and IDessert interfaces define common
methods and properties for the respective dish types. For example, IAppetizer has methods like
GetAppetizerName, GetCalories, PairWithBeverage, and PerformAppetizerFunction.
Concrete product classes like Edamame, Ramen, Mochi, Bruschetta, Pizza, Tiramisu, Kimchi,
Tokbokki, and Bingsu inherit from IAppetizer, IMainCourse, IDessert, inheriting methods such
as GetAppetizerName(), GetCalories(), and enabling specific implementations like SetWarm(),
SetClassic(), and PerformAppetizerFunction(). Each class defines specific methods and attributes
related to its type of dish. For example, Edamame has methods like GetAppetizerName,
GetCalories, SetWarm, SetCold, PairWithBeverage, and PerformAppetizerFunction.
3. IMPLEMENTATION
3.1 Code
The project file structure includes all the classes specified in the diagram. Each is placed in a
separate file.
Initialization(Tạ Minh Anh):
- The program starts by initializing empty lists for appetizers, mainCourses, desserts, and
selectedBeverages.
- Interfaces (IAppetizer, IMainCourse, IDessert) are defined to provide a blueprint for the concrete
dish classes.
- This interface has three abstract methods, each representing the creation of different types of
dishes in a restaurant
- The ItalianDishFactory, JapaneseDishFactory, and KoreanDishFactory classes are concrete
factories. Each of these classes implements the IRestaurantFactory interface, providing methods to
create objects of different types of dishes in the respective restaurant.
- First I declare a GetChoice method as a user input validation, it is a utility function used in the
program to obtain a valid numeric input from the user within a specified range (1 to maxChoice
inclusive).
maxChoice: Represents the upper limit of the valid choices the user can input.
Functionality:
The method enters an infinite loop with while (true), meaning it will keep asking for input until a
valid choice is provided.
The program prompts the user with "Enter your choice: " and attempts to read an integer from the
console input using Console.ReadLine().
Inside a try-catch block, it checks whether the input is a valid integer and falls within the range of 1
to maxChoice.
If the input is valid and within the specified range, the method returns the choice.
If the input is not a valid integer or is outside the specified range, it catches the exception, displays
an error message, and prompts the user to try again.
- The program displays a welcome message and enters a loop where the user can select a type of
dish: appetizer, main course, dessert, or exit.
In this code, the while (true) loop creates an infinite loop, ensuring that the program will continue to
run the code until a break statement is issued. In this loop, the selection menu for selecting the dish
type (Appetizer, Main Course, Dessert or Exit) is displayed on the console.
GetChoice(4) is called to get the user's choice, with argument 4 specifying that the user's choice
must be between 1 and 4 (inclusive). If the user selects 4 (Exit), the break statement is executed,
ending the loop and the program stops.
This allows the program to continuously display the menu, take the user's selection, and perform
actions corresponding to the selection until the user decides to exit the program by selecting option
4.
- Based on the user's choice, they are prompted to select a type of restaurant: Japanese, Italian, or
Korean.
The options are listed on the console with sequential numbers: 1. Japanese Restaurant, 2. Italian
Restaurant and 3. Korean Restaurant.
GetChoice(3) is called to get the user's choice between 1 and 3. The parameter 3 passed to the
GetChoice function specifies that the user's choice must be between 1 and 3 (inclusive).
After the user selects a restaurant, the value is stored in the variable restaurantChoice for use in
other parts of the program, to determine the type of restaurant the user has selected.
- Then, the user selects a beverage type: none, water, soda, tea, or coffee.
In this code, the program asks the user to select the type of drink they want with their dish. Options
displayed on the console include: 1. None, 2. Water, 3. Soda, 4. Tea and 5. Coffee.
GetChoice(5) is called to receive input from the user, ensuring that the choice is between 1 and 5.
The beverageChoice value is then converted to the enum type BeverageType by subtracting 1. This
is because enum BeverageType is defined so that the value of None is 0, Water is 1, Soda is 2, Tea
is 3 and Coffee is 4.
This conversion helps store information about the type of beverage the user has selected, so that The
program can later display complete information about the selected food and drink.
The default statement does not perform any action, if restaurantChoice is not 1, 2 or 3 then
restaurantFactory remains null. The user's choice of the restaurant of choice determines whether the
program will use any restaurant's factory to create the respective object dishes.
- The choice of factory determines the type of dishes that can be created.
In the above code, the value of the dishChoice variable is checked in a switch statement. If
dishChoice has a value of 1, the appetizer variable will be assigned the value of an appetizer object
created via the restaurantFactory's CreateAppetizer() method. If dishChoice is 2, the mainCourse
variable will be assigned the value of a main dish object created through the restaurantFactory's
CreateMainCourse() method. Finally, if dishChoice has a value of 3, the dessert variable will be
assigned the value of a dessert object created via the restaurantFactory's CreateDessert() method.
The other cases in the switch statement take no action, so if dishChoice is not 1, 2, or 3, the
appetizer, mainCourse, and dessert variables will hold null values. This choice reflects the dish the
user has selected (appetizer, main course or dessert) and depending on the type of restaurant they
have previously selected, corresponding food objects will be created and assigned into these
variables for use in the next steps of the program.
Dish Creation (Tạ Minh Anh):
- Inside the loop, the user's dish choice (appetizer, main course, or dessert) is evaluated.
+ Appetizer example:
Bruschetta is a class that represents an IAppetizer appetizer. This class has hasClassic,
hasSteakAndBlue, and hasChickenSalad properties, which are used to define custom versions of
Bruschetta.
The constructor (public Bruschetta()) is used to initialize the name of the dish as "Bruschetta". The
properties hasClassic, hasSteakAndBlue, and hasChickenSalad are initially set to false, only to be
set to true when the user selects the corresponding option during interaction.
GetAppetizerName() is a method of the Bruschetta class implemented from the IAppetizer
interface. This method returns the name of the dish, set in Bruschetta's constructor to "Bruschetta".
These attributes are then used in calculating the calorie count of the dish based on the customer's
preferences. This allows users to customize their Bruschetta as desired, making the restaurant
management system flexible and easy to use.
The GetCalories() method of the Bruschetta class calculates the calories of the dish based on the
customer's optional requests. Initially, the calorie value was set at 200, representing the basic calorie
count of Bruschetta.
If the customer chooses to request hasClassic, no calorie points are added because calories += 0;. If
they choose hasSteakAndBlue, 50 calories are added. Similarly, if they choose hasChickenSalad, 10
calories are added. These conditions represent the optional ingredients or requirements for which
Bruschetta can be made, and the calorie count is updated accordingly.
Finally, the value of calories after processing the optional requests is returned, representing the total
number of calories for the Bruschetta based on the customer's request. This allows the restaurant
management system to calculate and display accurate calorie information for the customized dish.
The method PairWithBeverage(BeverageType BeverageType) of class Bruschetta accepts a
parameter that is the type of drink (BeverageType BeverageType). This method is used to combine
the Bruschetta dish with the type of graph that the customer chooses. When called, this method will
display a screen describing the Bruschetta message job associated with the graph type selected by
the client.
The PerformAppetizerFunction() method of the Bruschetta class performs the function for selecting
the Bruschetta type. When called, this method will display on the console screen options for the
customer, including Classic Bruschetta, Steak and Blue Cheese Bruschetta and Chicken Salad
Bruschetta. The user enters his or her choice, and then the method uses a switch statement to
determine the choice and set the corresponding Bruschetta properties based on that choice.
For example, if the user selects Classic Bruschetta (choice 1), the method calls the SetClassic(true)
method to set the Bruschetta's hasClassic property to true. It will then display a message describing
that Classic Bruschetta has been selected and display the dish's calorie count using GetCalories().
Similar steps will be followed for the Steak and Blue Cheese Bruschetta and Chicken Salad
Bruschetta options.
Through this method, users can customize the type of Bruschetta they want to order, and then dish
and calorie information is displayed to provide insight into their selection.
+ Main course example(Đoàn Võ Quý):
If the user chooses Main Course and Italian restaurant, ItalianDishFactory.CreateAppetizer() creates
a Pizza object.
This Pizza class implements the IMainCourse interface and represents a type of main course in the
World Flavors Restaurant. The class contains private boolean variables (hasCheese, hasVeggie,
hasPepperoni, hasExtraCheese, hasExtraVeggie, and hasExtraPepperoni) to track the customization
options for the pizza. The constructor sets the initial name of the pizza as "Pizza". The
GetMainCourseName method returns the name of the main course.
This class, like the other dish classes, is designed to be customizable. Users can choose various
options such as adding extra cheese, extra vegetables, or extra pepperoni to their pizza. The
customization options affect the calorie count, allowing for a personalized dining experience. The
class's methods and properties allow for the dynamic creation and customization of different pizza
types within the program.
The Pizza class includes several setter methods (SetCheese, SetVeggie, SetPepperoni,
SetExtraCheese, SetExtraVeggie, and SetExtraPepperoni) that allow users to customize their pizza
based on different ingredients. These methods take a boolean value as input and set the
corresponding boolean variables (hasCheese, hasVeggie, hasPepperoni, hasExtraCheese,
hasExtraVeggie, and hasExtraPepperoni) accordingly. When a particular ingredient is set to true, it
indicates that the pizza includes that ingredient in its preparation.
These methods are essential for enabling user interaction and customization in the program,
allowing users to create their desired pizza by selecting various ingredients and additions.
The GetCalories method in the Pizza class calculates the total calories of the pizza based on its
ingredients. It starts with a base calorie count of 200. Depending on the selected ingredients and
customizations (such as regular cheese, extra cheese, vegetables, and pepperoni), the method adds
specific calorie values for each ingredient. For example, if the pizza has regular cheese, it adds 0
calories, if it includes extra cheese, it adds 120 calories, if it has vegetables, it adds 10 calories, and
so on. By summing up these calorie values based on the selected ingredients and customizations, the
method computes the total calorie count for the pizza, providing an accurate representation of its
nutritional content for the customers.
The method PairWithBeverage(BeverageType BeverageType) of class Bruschetta accepts a
parameter that is the type of drink (BeverageType BeverageType). This method is used to combine
the Pizza dish with the type of graph that the customer chooses. When called, this method will
display a screen describing the Pizza message job associated with the graph type selected by the
client.
In the PerformMainCourseFunction method of the Pizza class, the program presents the customer
with options to choose the type of pizza: Cheese Pizza, Veggie Pizza, or Pepperoni Pizza. The
GetChoice(3) method ensures the input is valid and corresponds to one of the available pizza
options.
Upon receiving the customer's choice, the method sets the appropriate boolean flags (hasCheese,
hasVeggie, or hasPepperoni) to true based on the selected pizza type. After setting the flags, the
method calculates and displays the total calories of the selected pizza configuration using the
GetCalories() method. The _name variable is updated to reflect the chosen pizza type (e.g., "Cheese
Pizza") for later reference.
After the customer selects the type of pizza (Cheese Pizza, Veggie Pizza, or Pepperoni Pizza), the
program asks the customer if they want to customize their pizza. It presents options for
customization, such as adding Extra Cheese, Extra Vegetable, or Extra Pepperoni. The customer can
choose one of these options or press 4 to indicate that they are done customizing their pizza.
Inside the while loop, the program continuously prompts the customer to choose a customization
option until they press 4 to indicate they are finished. Depending on the customer's choice, the
corresponding boolean flags (hasExtraCheese, hasExtraVeggie, or hasExtraPepperoni) are set to
true. After each customization, the program calculates and displays the updated total calories of the
pizza configuration using the GetCalories() method, considering the additional toppings.
This interactive customization process allows customers to tailor their pizza according to their
preferences, providing a personalized dining experience. The program ensures accurate calorie
calculation by updating the calorie count with each customization choice made by the customer.
+ Dessert example (Đoàn Võ Quý):
If the user chooses Dessert and Korean restaurant, KoreanDishFactory.CreateAppetizer() creates the
Bingsu object.
The Bingsu class implements the IDessert interface and represents a dessert item in the restaurant
menu. It has various customization options for customers to choose from, including Traditional,
Fruity, Chocolate, Extra Sweet, or None. The Bingsu class includes boolean flags such as
hasTraditional, hasFruity, hasChocolate, hasExtraSweet, and hasNone to keep track of the
customer's customization preferences.
The class has a constructor Bingsu() that initializes the dessert name as "Bingsu". It also
implements the GetDessertName() method from the IDessert interface, which returns the dessert's
name, allowing other parts of the program to access the dessert's name without directly accessing its
private fields.
Similar to the Bruschetta and Pizza classes, the Bingsu class would also include methods for setting
the customization options (such as SetTraditional(bool value), SetFruity(bool value),
SetChocolate(bool value), SetExtraSweet(bool value), and SetNone(bool value)) and calculating the
total calories based on the selected options (implemented in a GetCalories() method). Additionally,
there would be a method PerformDessertFunction() to interactively guide the customer through the
dessert customization process, allowing them to select their preferred options.
The Bingsu class includes several setter methods (SetTraditional(bool value), SetFruity(bool value),
SetChocolate(bool value), SetExtraSweet(bool value), and SetNone(bool value)) that allow
customers to customize their dessert preferences. These methods set the corresponding boolean
flags (hasTraditional, hasFruity, hasChocolate, hasExtraSweet, and hasNone) based on the user's
choices. When a customer selects a specific option during the dessert customization process, the
corresponding setter method is called with the value true, indicating that the particular
customization option has been chosen.
The GetCalories() method in the Bingsu class calculates the total calories of the dessert based on the
customer's customization preferences. The method starts with a base calorie value of 200 and then
adds additional calories based on the selected options.
If the customer chooses the Traditional option, no extra calories are added (calories += 0). If the
customer chooses the Fruity option, 10 extra calories are added (calories += 10). If the customer
chooses the Chocolate option, 15 extra calories are added (calories += 15). If the customer chooses
the ExtraSweet option, 120 extra calories are added (calories += 120). If the customer chooses the
None option, no extra calories are added (calories += 0).
The final calories value represents the total calorie count of the customized dessert, considering the
selected options. This method provides an accurate calorie count for the customer's personalized
dessert, allowing them to make informed choices based on their dietary preferences and
requirements.
The PairWithBeverage(BeverageType beverageType) method in the Bingsu class is used to pair the
customized Bingsu dessert with a specific beverage type. When called, this method takes a
BeverageType as a parameter, representing the chosen beverage to pair with the dessert. The
method then prints a message to the console indicating the pairing, stating that the Bingsu dessert is
paired with the specified beverage type.
This method provides flexibility for customers to choose their preferred beverage to complement
the flavors of the Bingsu dessert, enhancing their overall dining experience.
The PerformDessertFunction() method in the Bingsu class allows customers to choose the type of
Bingsu dessert they want. It displays a menu with different options, including "Traditional Bingsu,"
"Fruity Bingsu," and "Chocolate Bingsu." The customer can enter their choice, and based on the
selection, the corresponding boolean variables (hasTraditional, hasFruity, hasChocolate) are set to
true, indicating the customer's choice.
For example, if the customer chooses "Fruity Bingsu" (option 2) by entering 2: The method sets the
hasFruity variable to true and updates the _name property to "Fruity Bingsu." It then prints the
calorie count of the chosen dessert and the name of the dessert with the corresponding calories.
The code displays a menu for customizing the Bingsu dessert. Customers are given options to add
extra sweetness or opt for no customization. The PerformDessertFunction() method allows
customers to choose additional customization for their Bingsu dessert.
When the customer selects option 1 ("Extra Sweet"), the SetExtraSweet(true) method is called,
indicating that the customer wants extra sweetness added to their dessert. The calorie count is
updated accordingly, and a message is displayed confirming the addition of extra sweetness. If the
customer selects option 2 ("No custom"), the SetNone(true) method is called, indicating that no
additional customization is desired. The calorie count remains the same, and a message confirms
that no customization has been added. If the customer enters an invalid choice, an error message is
displayed, indicating that the choice is not valid.
The customization process continues in a loop until the customer chooses option 3 ("Done"). At that
point, the loop exits, and the message "Bingsu customization completed" is displayed, indicating the
end of the customization process. This approach ensures that customers have the flexibility to
personalize their dessert according to their preferences.
Error Handling(Đoàn Võ Quý):
In this block, the program catches any exception of type System. Exception that might occur during
the execution of the code within the try block. Exceptions are unexpected events that can occur
during the execution of a program, such as invalid input or other runtime errors.
When an exception of type System.Exception occurs (which is a general exception type that can
catch any exception), the program executes the code inside the catch block. In this case, it prints an
error message to the console, indicating that the user has provided invalid input and prompts them
to enter a valid number.
This catch block ensures that the program does not crash if an exception occurs during the
execution of the code inside the try block. Instead, it handles the exception gracefully by displaying
an error message, allowing the program to continue running without interruption.
Recording Selections:
Each selected dish object (implementing IAppetizer, IMainCourse, or IDessert) is stored in the
respective list (appetizers, mainCourses, or desserts).
The code above checks whether the user has selected an appetizer, a main course, or a dessert. If the
user has selected a food type, the corresponding PerformAppetizerFunction() method is called to
allow them to customize their selection. After the user completes the selection, information about
the selected dish and drink is displayed via DisplayAppetizerInfo(). Similarly, if the user selects a
main course (mainCourse), PerformMainCourseFunction() is called to customize their main course
and then detailed information is displayed via DisplayMainCourseInfo(). If the user selects a
dessert, PerformDessertFunction() is called to allow them to customize their selection and the
information is displayed via DisplayDessertInfo().
Finally, each dish or drink type is added to the corresponding list (appetizers, mainCourses,
desserts) to track customer order information.
These static methods, DisplayAppetizerInfo, DisplayMainCourseInfo, and DisplayDessertInfo, are
responsible for displaying the selected food items and their corresponding beverage choices. They
take the selected IAppetizer, IMainCourse, or IDessert object, and the chosen BeverageType as
parameters. When called, these methods print out the name of the selected food item and the chosen
beverage to the console, providing the user with a summary of their order.
This section of the code is responsible for displaying a summary of the user's order. It starts by
iterating through the appetizers, mainCourses, and desserts lists, printing the name of each selected
item along with its calorie count (retrieved using the GetCalories method) and the corresponding
chosen beverage (selectedBeverages[i]). This information is displayed for each appetizer, main
course, and dessert that the user selected. Finally, it prints a thank you message, indicating the end
of the dining experience at the World Flavors Restaurant.
After the user exits the dish selection loop (chooses to exit the program), the program displays the
selected dishes and their corresponding beverage choices. It iterates over the lists of selected dishes,
retrieving their names and calorie counts, and displays this information to the user.
This portion of the code ensures that the user gets a clear overview of their order before exiting the
program.
Termination Message:
Finally, the program displays a thank you message, indicating the end of the dining experience.
This flow demonstrates the dynamic creation of different types of dishes based on user preferences
and the decoupling of client code from the concrete classes, which is a fundamental characteristic of
the Abstract Factory Pattern.
This approach allows for easy extension of the application by adding new types of dishes and
restaurants without modifying the existing code structure.
3.2 Program screenshots:
4. Discussion
4.1. Range of similar patterns
Factory Method Pattern:
The Factory Method pattern defines an interface for creating an object, but it lets subclasses alter
the type of objects that will be created. Subclasses are responsible for implementing the method to
create objects. This pattern allows a class to delegate the responsibility of instantiating its objects to
its subclasses.
Use Case: Suitable when a class can't anticipate the class of objects it needs to create. It lets
subclasses decide which class to instantiate.
Builder Pattern:
The Builder pattern separates the construction of a complex object from its representation,
allowing the same construction process to create various representations. It provides a way to
construct a complex object step by step. The Director class orchestrates the construction process via
an interface (Builder) abstracting the steps.
Use Case: Useful when creating objects with many optional components or configurations. It
provides clear steps to build an object with specific characteristics.
Prototype Pattern:
The Prototype pattern creates new objects by copying an existing object, known as the prototype.
Instead of creating objects from scratch, this pattern involves cloning an existing object. The
prototype object serves as a blueprint for creating new objects, and clients can create new instances
by copying the prototype.
Use Case: Ideal when creating objects is more expensive than copying existing ones, and when
the type of objects is determined at runtime based on existing instances.
Why the Abstract Factory pattern is the most suitable for my project:
Multiple Object Families: The Abstract Factory pattern is suitable for projects where multiple
related object families need to be created simultaneously. In my restaurant project, different types of
appetizers, main courses, and desserts are created together based on the chosen restaurant type. The
Abstract Factory pattern encapsulates the creation logic for all these related objects.
Consistent Interfaces: Abstract Factory ensures that the created objects adhere to consistent
interfaces (like IAppetizer, IMainCourse, IDessert). This consistency simplifies the interaction
between different types of dishes and beverages, ensuring a seamless experience for my customers.
Easy Extensibility: If I want to add more types of restaurants or expand the variety of dishes in
the future, the Abstract Factory pattern allows me to introduce new concrete factories without
modifying existing code. This extensibility makes my project more adaptable to changes and
additions.
Encapsulation of Creation Logic: Abstract Factory encapsulates the creation logic within
concrete factories. This encapsulation keeps the complexities of object creation hidden from the
client code, promoting modularity and maintainability in my application.
My program demonstrates the use of abstract factory patterns, enhancing the code's organization,
reusability, and readability. The Abstract Factory Pattern provides a structured way to create families
of related or dependent objects without specifying their concrete classes. While it offers clear
advantages in terms of maintainability, flexibility, and consistency, it might introduce complexity in
larger applications and require careful management of class relationships.
Advantages:
Separation of Concerns: The Abstract Factory Pattern separates the process of object creation
from the usage of objects. This separation maintains a clear distinction between different tasks and
adheres to the Single Responsibility Principle, making our codebase easier to maintain. For example,
in our project, the ItalianDishFactory class is responsible for creating Italian dishes like Bruschetta,
Pizza, and Tiramisu. This separation allows focusing on different types of dishes without impacting
each other's creation logic.
Flexibility and Scalability: This pattern allows for easy scalability. Adding new types of dishes or
restaurants is straightforward; we just need to create new factory classes. This flexibility ensures my
codebase can easily accommodate new additions without extensive modifications.
Consistency Across Products: Abstract Factory Pattern ensures that the created objects are
compatible with each other. For example, an appetizer created by a specific factory will always be
compatible with the main course and dessert created by the same factory. This ensures a consistent
user experience.
Encapsulation of Creation Logic: The pattern encapsulates the creation logic within concrete
factory classes. This encapsulation makes it easier to change or extend the creation process without
affecting the client code, enhancing maintainability and reducing the risk of introducing errors. For
example, the logic for creating Bruschetta's variations (Classic, Steak and Blue Cheese, Chicken
Salad) is encapsulated within the Bruschetta class. Modifying or extending these variations won't
affect other parts of the system.
Promotes Coding to Interfaces: By using interfaces like IAppetizer, IMainCourse, and IDessert,
the pattern promotes coding to interfaces rather than concrete implementations. This allows for
substitutability and dependency injection, making the code more modular and testable.
Disadvantages:
Complexity in Large Applications: The Abstract Factory Pattern can introduce complexity,
especially in larger applications with numerous products and families of products. Managing a large
number of factory classes and their relationships can be challenging. For example, as our restaurant
menu expands, managing multiple factories (ItalianDishFactory, JapaneseDishFactory, etc.) for
various cuisines can become complex.
Increased Number of Classes: Introducing new products or variations can lead to an explosion of
classes. For every new dish or restaurant type, you need to create multiple new classes (interfaces,
concrete classes, and factories), potentially cluttering the codebase. For example, adding a new
dessert might require creating a new concrete class implementing IDessert, potentially leading to a
large number of classes in your system.
REFERENCES
Bishop, J., 2008. C# 3.0 Design Patterns: Use the Power of C# 3.0 to Solve Real-World Problems. 1st ed.
s.l.:O'Reilly Media.
Tutorial(2022).Adapter.[Online].TutorialspointAvailableat:
https://www.tutorialspoint.com/design_pattern/adapter_pattern.htm