0% found this document useful (0 votes)
168 views

APDP Assignment Final TYYS

Uploaded by

vantekim957
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)
168 views

APDP Assignment Final TYYS

Uploaded by

vantekim957
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 91

APPLIED PROGRAMMING & DESIGN PRINCIPLE

Student Name – Toe Yuya San

Student ID – RF 17809

Unit Tutor - Ms. Ei Ei Mon

Assignment Title - Implementation of Data Processing Application using


SOLID Principles
HND-50 Toe Yuya San
Table of Contents
Introduction ......................................................................................................... 4
Object Oriented Programming (OOP) ....................................................................... 4
Key components of object-oriented programming ................................................... 5
Types of Relation Between Classes in Object Oriented Programming .......................... 7
Association ..................................................................................................... 7
Inheritance ..................................................................................................... 8
Composition .................................................................................................... 9
Aggregation .................................................................................................... 9
SOLID Principles in OOP ........................................................................................ 10
Single-responsibility Principle (SRP) ..................................................................... 11
Open-closed Principle (OCP) ................................................................................ 12
Liskov Substitution Principle (LSP) ....................................................................... 14
Interface Segregation Principle (ISP) .................................................................... 15
Dependency Inversion Principle (DIP) ................................................................... 16
The impact of clean coding techniques on the use of data structures and operations when
writing algorithms ................................................................................................ 18
Best practices to write Clean Code ....................................................................... 22
Analyzing the relationship between Object Oriented Programming and Design Pattern ... 23
Interdependence of OOP and Design Patterns ........................................................ 24
Design Pattern in Object-Oriented Programming ....................................................... 25
Reason for using Design Pattern in OOP ................................................................ 25
Analysis report on design patterns .......................................................................... 26
Creational Patterns ............................................................................................ 26
Structural Patterns ............................................................................................ 28
Behavioral patterns ........................................................................................... 30
Evaluating Solid Principles and their impact on Objected Oriented application development
......................................................................................................................... 32
UML class diagram of SOLID Principles .................................................................... 33
S - Single-responsibility Principle (SRP) ................................................................ 33
O - Open-closed Principle (OCP) .......................................................................... 35
L - Liskov Substitution Principle (LSP) .................................................................. 36
I - Interface Segregation Principle (ISP) ............................................................... 37
D - Dependency Inversion Principle ...................................................................... 39
UML class diagram of Design Patterns ..................................................................... 41
1
HND-50 Toe Yuya San
Creational Design Patterns .................................................................................. 42
Singleton pattern ............................................................................................ 42
Factory Method Pattern ................................................................................... 43
Structural Design Patterns .................................................................................. 45
Adapter Pattern .............................................................................................. 45
Decorator Pattern ........................................................................................... 46
Behavioral Design Patterns ................................................................................. 48
Observer Pattern ............................................................................................ 48
Strategy Pattern ............................................................................................. 51
Class diagram of given code scenario including multiple design patterns ...................... 54
Singleton Patterns ............................................................................................. 54
Factory Method Pattern ...................................................................................... 55
Adapter Pattern ................................................................................................. 56
Decorator Pattern .............................................................................................. 58
Observer Pattern ............................................................................................... 59
Strategy Pattern ................................................................................................ 60
Code by using SOLID principles with design pattern .................................................. 61
Single Responsibility Principle (SRP) ..................................................................... 64
Open/Closed Principle (OCP) ............................................................................... 64
Liskov Substitution Principle (LSP) ....................................................................... 64
Interface Segregation Principle (ISP) .................................................................... 65
Dependency Inversion Principle (DIP) ................................................................... 65
Design Patterns ................................................................................................. 65
Clean Coding Method ......................................................................................... 66
UML class diagram of my application ....................................................................... 67
UI Design Explanation ........................................................................................... 70
Login Page ....................................................................................................... 70
Register Page ................................................................................................... 72
List of Car Page ................................................................................................. 73
Search Data ..................................................................................................... 75
Update Page ..................................................................................................... 76
Different methods of implementing automatic testing as designed in the test plan ......... 77
Unit testing ...................................................................................................... 77
Integration testing ............................................................................................. 78
System testing .................................................................................................. 78
2
HND-50 Toe Yuya San
The differences between developer produced and vendor provided automatic testing tools
for applications and software systems ..................................................................... 78
Developer produced tools ................................................................................... 78
Katalon Studio ............................................................................................... 79
OpenTest....................................................................................................... 79
Cypress ......................................................................................................... 80
Vendor provided tools ........................................................................................ 80
Gatekeeper .................................................................................................... 80
Cflow ............................................................................................................ 81
Genuity ......................................................................................................... 82
Comparison Table ........................................................................................... 82
Different form of automatic testing ......................................................................... 83
Integration testing ............................................................................................. 83
Widget testing .................................................................................................. 83
Pros of widget testing ...................................................................................... 84
Cons of widget testing ..................................................................................... 85
Unit testing ...................................................................................................... 85
Pros of widget testing ...................................................................................... 86
Cons of unit testing ......................................................................................... 87
Demonstration ..................................................................................................... 87
References .......................................................................................................... 89

3
HND-50 Toe Yuya San

Introduction

I'm dedicated to helping Myan Pro Solutions develop and enhance its software
solutions as a junior mobile developer. In addition to creating mobile applications,
my job also includes improving our internal documentation procedures. For our
internal libraries to be reused and maintained across several projects, effective
documentation is essential.

I was recently tasked with creating and implementing a mobile application for
Prestige Automobiles Company Limited (PAC), which is authorized to import and
distribute genuine BMW parts as well as automobiles in Myanmar. For this project,
a thorough grasp of programming concepts, the use of design patterns, and
adherence to SOLID guidelines are required. The main goal is to develop a
productive and easy-to-use app that enables PAC to easily manage their inventory
of cars.

I will discuss the value of UML diagrams and design patterns, provide an
example of how SOLID principles are applied, and show off clean coding techniques
in this document. The PAC app will be better off thanks to these approaches, which
will also help junior developers comprehend and use these best practices in other
projects.

Object Oriented Programming (OOP)

Programming paradigms, or classifications, that arrange a collection of data


attributes with functions or methods into a unit called an object are called object-
oriented programs.

4
HND-50 Toe Yuya San
OOP languages are typically class-based, which means that an instance of a class
serves as a blueprint for creating objects, which are instances of the class, and
defines the attributes of the data.

Many independent objects that interact with one another in intricate ways may be
represented by a single class. The class-based programming languages C++,
Python, and Java are widely used. (Herrity, 2023)

Key components of object-oriented programming

• Class - A class is a type of data that offers an object creation framework. To


create multiple objects without writing additional code, you can define a class.
• Object - In object-oriented programming, an object is a creation, or instance,
of a class. In order to execute code, objects define particular data, like
properties and behaviors.
• Attribute - This structure describes the state of an object and stores data
about it. As a component of the class, an attribute can be defined.
• Method - A method is a function that carries out an operation or task. For
instance, a method might provide data about an object.

• Encapsulation - Encapsulation is the process of enclosing data inside an


object. Encapsulation creates a wall around data in OOP to keep it safe from
the rest of the code. By incorporating the data and its functions into a class,
encapsulation can be accomplished. This action only reveals the functionality
required to interface with a class; it hides all other details. A class is
considered well-encapsulated when it prevents direct access to its private
data.
Example - If you're making a class to represent an individual, you can specify
private information like the individual's Social Security number. This data can

5
HND-50 Toe Yuya San
be contained within a private variable in the class so that it is inaccessible
from outside code. The function may use the data variable as needed if you
write a method in the person class to carry out a bank transaction. In this
instance, the class effectively encapsulates the individual's private
information.

• Abstraction - When you access objects using simplified classes instead of


complicated implementation code, this is called abstraction. It's often easier
to write code when you can keep a class's interface separate from how it
works. Through the class member functions in OOP, you can hide the
implementation details of a class and give it a clean, easy-to-use style. When
you change the code, abstraction helps separate the effects so that if
something goes wrong, the change only impacts the implementation details
of a class and not the code that runs outside of it.
Example - Think of a stereo system as a thing that has a complicated logic
board inside it. The stereo system has buttons on the outside to allow for
interaction with the object. You can't see what happens inside the logic board,
but when you press a button, it does something to turn on the system. This
example shows the principle of abstraction, which you can apply widely in
object-oriented programming.

• Polymorphism - The creation of objects with shared behaviors is referred to


as polymorphism. Polymorphism in OOP enables classes to be treated
consistently in a hierarchy. Any objects created by a child class within the
hierarchy have the same functions when you write code for objects at the root
of the hierarchy. An object may behave differently depending on what kind it
is.
Example - You can write a class function to generate noise if your animal
class has two child classes, cat and dog. You can override this function that

6
HND-50 Toe Yuya San
the dog and cat child classes inherit by using polymorphism. Alternatively, you
can set this function to "bark" for dogs and "meow" for cats. An animal object
that passes through the interface will either "meow" or "bark" in response to
its surroundings.

• Inheritance - Because inheritance is supported by a wide range of object-


oriented languages, a new class inherits its parent class's functionalities and
properties by default. Classes can be arranged systematically through
inheritance, where a class may have one or more parent or child classes. A
class is said to have inherited its parent's properties if it has a parent class.
The behavior of the parent class can also be expanded upon or changed by
the child class. You can reuse code through inheritance without rewriting a
child class's functions.

Example - An insect, for example, may be a member of an insect class in the


animal kingdom. All insects in this class have the same characteristics, like
having six legs and an exoskeleton. For various insect species, like
grasshoppers and ants, you can make subclasses. These child classes share
the same characteristics as the insect class since they inherit its properties.

Types of Relation Between Classes in Object Oriented Programming

Association
An association is a loosely connected class relationship in which each class
exists independently of the others. It frequently serves to depict a straightforward
connection between two objects. As an example,

7
HND-50 Toe Yuya San

A Student class and a Course class are associated in this example. Although a
Student may register for more than one course, each course is a separate entity.

Inheritance
A fundamental concept in object-oriented programming (OOP) is inheritance,
which allows a new class take on the attributes and actions of an old class. Code
reuse is encouraged and a "is-a" relationship is represented. As an illustration,
consider this:

The Animal base class in this example has a speak() function and a name
property. In addition to inheriting from Animal, the Dog class also has a bark()
method and a breed property.

8
HND-50 Toe Yuya San
Composition
One class is composed of other classes, and the existence of the parts is
necessary for the existence of the whole, illustrating a strong relationship between
the classes. It's employed to combine simpler objects to create more complex ones.
This is an example,

An Engine makes up the Car class in this example. The Engine is an integral part
of the Car and is necessary for the Car to operate.

Aggregation
Although the pieces can exist separately, aggregation is a weaker relationship
in which one class contains other classes. It is applied to parts that can be shared
by several entire objects and have their own life cycle. As an example, take a look
at this:

9
HND-50 Toe Yuya San

In this instance, there is an aggregation relationship between the Employee class


and the Department class. The Department may consist of several employees,
each of whom may function independently. (Khan, 2023)

SOLID Principles in OOP

The first 5 object-oriented design (OOD) principles established by Robert C.


Martin are referred to as SOLID.

These instructions set forth best practices for creating software while taking
into account its ongoing maintenance and expansion as the project develops. Using
these techniques can also aid in the development of Agile or Adaptive software, the
avoidance of code smells, and code rewriting.

SOLID stands for:

S - Single-responsibility Principle

O - Open-closed Principle

L - Liskov Substitution Principle

10
HND-50 Toe Yuya San
I - Interface Segregation Principle

D - Dependency Inversion Principle

Single-responsibility Principle (SRP)

According to the Single Responsibility Principle (SRP), a class should only be


altered for one reason at a time. Following this rule in the context of Flutter
development entails segmenting code into more manageable, focused classes, each
with a specific duty. Code that adheres to SRP is easier to test, reuse, and maintain
in the future.

Tips for Implementing SRP

Establish Single-Responsibility Classes and Functions: Every class and


function need to have a distinct role. This clarity facilitates comprehension of the
code and guarantees that modifications made to one section won't unintentionally
impact other sections.

Refactor When Necessary: It's critical to refactor a class or function that begins
to take on excessive responsibility. Break the code up into smaller, more
manageable parts, each handling a single task. This separation improves the code's
manageability while also making it simpler.

Use Mixins and Composition: Use mixins or composition to prevent the creation
of monolithic "god classes" that manage several tasks. By separating concerns,
these techniques let each section of the code concentrate on a specific facet of the
overall functionality.

Writers can write code that is easier to read and maintain by using SRP. This idea is
fundamental to building reliable software that can change subtly over time.

Code example,
11
HND-50 Toe Yuya San

Open-closed Principle (OCP)

Code that is closed to modification but open for extension is encouraged to be


designed according to the Open-Closed Principle (OCP). This refers to building a
system in Flutter development where new features and behaviors can be added
without changing the code that already exists. Developers can add functionality
while preserving the integrity and stability of the current codebase by utilizing OCP.

Tips for Implementing OCP

Design Classes and Modules for Extension: Make sure the modules and classes
you create can have additional features added to them in the future. Clear interfaces
and abstract classes that capture common behavior must be defined in order to
facilitate future development without requiring modifications to the original code.

Utilize Inheritance, Interfaces, and Abstract Classes: To build base classes


that more specialized classes can extend, use inheritance. Create interfaces to
12
HND-50 Toe Yuya San
specify expected behaviors that different classes can follow. In order to maintain
consistency in the fundamental structure, abstract classes can offer a common base
upon which various subclasses can build.

Apply Polymorphism for Flexible Behavior Extension: To extend flexible


behavior, use polymorphism. This technique lets objects be treated more like
instances of their parent class than like members of their own class. This makes it
possible for various classes to inherit from the same base class or implement the
same interface, offering a flexible and dynamic method of extending functionality.

Flutter application developers can create more flexible and manageable applications
by following the Open-Closed Principle. This methodology guarantees the code's
durability and adaptability to modifications, promoting the software's ongoing
enhancement and development.

Code example,

13
HND-50 Toe Yuya San

Liskov Substitution Principle (LSP)

According to the Liskov Substitution Principle (LSP), derived classes must be


interchangeable with their base classes without affecting the program's correctness.
This principle maintains consistency and maintainability in Flutter code by requiring
subclasses to abide by the contract established by their parent classes.

Tips for Implementing LSP:

Ensure Substitutability: Derived classes should be compatible with their base


classes without compromising the correctness of the program. This is one of the
most important implementation tips for LSP. Essentially, this means that subclass
objects can be swapped out for superclass objects without compromising the
behavior of the application.

Use Dart's Type System: To effectively use the type system in Dart, define
contracts using interfaces or abstract classes. Incorporating the anticipated behavior
of the base class into subclasses is enforced through this.

Follow Method Contracts: Make sure subclass overriding methods respect the
base class's contract. It is expected that the overridden methods adhere to the
behavior of the base class in addition to matching the method signatures.

Code example,

14
HND-50 Toe Yuya San

Interface Segregation Principle (ISP)

It is against the Interface Segregation Principle for clients to be made


dependent on interfaces they do not use. This idea promotes the development of
focused interfaces in Flutter by defining only the methods that are actually needed.
Following ISP reduces interface bloating, enhances code readability, and increases
code adaptability.

Tips for Implementing ISPs:

Make customized user interfaces that address the requirements of the clients who
utilize them.

Don't make interfaces that are too big and have too many methods.

When necessary, implement several smaller interfaces and allow clients to select
the interfaces they require.

Code example,

15
HND-50 Toe Yuya San

Dependency Inversion Principle (DIP)

By encouraging a design in which high-level modules define their behavior


through interfaces or abstract classes, DIP addresses the problem of tight coupling
between modules. As a result, they can communicate with services or modules at a
lower level without having to rely on their actual implementations. For example, DIP
recommends defining an interface that describes the required data operations in a
Flutter application rather than using a specific database implementation directly.
Then, high-level modules can rely on this interface, making it possible to switch
between database implementations seamlessly without compromising the essential
features.
16
HND-50 Toe Yuya San

Tips for Implementing DIP:

Depend on Abstractions: Instead of using concrete classes for interaction, design


modules to work with interfaces or abstract classes. By protecting high-level
modules from modifications made to lower-level implementations, this strategy
encourages stability and maintainability.
Utilize Dependency Injection: Rather than building dependencies from scratch, use
dependency injection techniques to inject them into classes. Because different
dependency implementations can be simply swapped out during testing or
production, this increases the flexibility of classes.
Use containers for Inversion of Control (IoC): IoC containers automate an
application's dependency management. They lessen the complexity of manual
dependency injection by making it easier to configure and resolve dependencies
based on predefined rules.
Developers using Flutter can create modular, extensible, and more manageable
applications by implementing the Dependency Inversion Principle effectively. This
approach encourages appropriate design techniques that comply with industry
standards in addition to improving the quality of the code.

Code example

17
HND-50 Toe Yuya San

The impact of clean coding techniques on the use of data


structures and operations when writing algorithms

Clean Code is code that is structured and consistent so that it is easy to read,
maintain, understand, and change. It is also strong and safe so that it can meet
performance needs. It gets the most value out of software by making sure it is clear,
easy to maintain, and reliable.

Readability - Clean Code is simple to read, which helps other developers


understand and change it. This is very important for projects where people work
together or where different developers need to access the same codebase.

18
HND-50 Toe Yuya San
Example:v

The updated code is simpler to read since it makes use of descriptive variable names
(numbers for l and numbers for i).

Scalability: Scalability is also increased in clean code. Well-structured code makes


it simpler to add new features and alter current ones. This is crucial for projects that
are anticipated to expand or change.

Example:

19
HND-50 Toe Yuya San

The updated code makes it simple to add new report types without changing the
existing code by using specific implementations (PDFReport, CSVReport) and an
abstract class called Report.

Maintainability - It's also easier to keep clean code up to date. It's easier to find
and fix problems in code that is well-structured and follows standard practices. This
reduces the overall time and effort required to maintain a codebase.

Example:

20
HND-50 Toe Yuya San

Duplicate values are avoided and the function improves with the new addToList
function, which makes sure the value is added only if it does not already exist in the
list.

Efficiency: Lastly, it is more efficient to write clean code. Clean code takes less
time to read and comprehend, which helps with change requests and problem
solving. This can lower maintenance costs and accelerate overall development.

Example:

The improved 'processData' method reduces unnecessary sorting operations and


boosts efficiency by first filtering the list to extract only even numbers, and then
sorting the filtered list.

21
HND-50 Toe Yuya San
In general, a software project's success depends heavily on the quality of the
code that is written. It results in improved readability, maintainability, scalability,
and efficiency, which facilitates the efficient and manageable delivery of high-quality
products.

Best practices to write Clean Code

Avoid Hard-Coded Numbers

Rather than using hard-coded values, use named constants. This procedure makes
code modification easier and more clear.

Use Meaningful and Descriptive Names

In order to render the code more comprehensible and self-documenting, variables,


functions, and classes should have names that accurately represent their functions
and behavior.

Use Comments Sparingly and Make Them Meaningful

Comments should only be utilized sparingly and to provide pertinent context.


Overuse or imprecise comments can cause confusion and clutter in the codebase.

Write Short Functions That Perform a Single Task

Functions need to follow the Single Responsibility Principle (SRP), efficiently


completing a single task. This facilitates testing and improves the readability,
comprehension, and maintainability of functions.

22
HND-50 Toe Yuya San
Use the DRY (Don't Repeat Yourself) Principle

Functions, classes, modules, libraries, and other abstractions can be used to reuse
code and prevent code duplication. By lowering the likelihood of mistakes and bugs,
this technique improves the efficiency, consistency, and maintainability of code.

The development process gains increased readability, scalability,


maintainability, and efficiency by using these clean coding techniques. This
guarantees that the code is easy to read and change, which promotes the success
of projects over the long run. (blog.codacy, 2023)

Analyzing the relationship between Object Oriented


Programming and Design Pattern

Principles of OOP

Four fundamental concepts such as encapsulation, abstraction, inheritance,


and polymorphism define object-oriented programming. These guidelines make it
easier to write reusable, scalable, and modular code. Encapsulation makes sure that
only the parts of an object that are required are exposed through a public interface,
keeping the internal state of the object hidden from view. Modeling entities and
processes from the real world through abstraction makes complex systems simpler.
Because inheritance makes it possible to create new classes based on preexisting
ones, it encourages the reuse and extensibility of code. Because polymorphism
allows objects to be viewed as instances of their parent class, method invocation
can be flexible and dynamic.

Design Pattern

23
HND-50 Toe Yuya San
Reusable solutions for recurring issues in software design are known as design
patterns. They give developers a common language and encapsulate best practices.
The three primary categories of design patterns are structural, behavioral, and
creative patterns. In order to provide effective and adaptable instantiation,
creational patterns concentrate on object creation mechanisms. By using simpler
components to create complex structures, structural patterns address object
composition. Behavioral patterns help to clarify and maintain code behavior by
defining how objects interact and communicate.

Interdependence of OOP and Design Patterns

Foundation of Design Patterns in OOP Principles: OOP principles form the


fundamental basis of design patterns. Patterns like the Facade, which conceal
complex subsystems behind a straightforward interface, require encapsulation. The
Factory Method and Abstract Factory patterns, which offer interfaces for creating
objects without defining their precise classes, depend on abstraction. Patterns like
Template Method and Strategy, which permit subclasses to override methods and
enable dynamic behavior changes, are based on inheritance and polymorphism.

Improvement of OOP through Design Patterns: Design patterns improve OOP


by offering organized solutions to typical design problems. As an example, the
Decorator pattern follows the Open/Closed Principle by dynamically extending an
object's functionality without changing its code. By severing the subject from its
observers, the observer pattern encourages loose coupling and improves
maintainability. These patterns provide reliable, scalable, and reusable design
solutions by utilizing OOP principles.

Using Design Patterns to Handle OOP Limitations: OOP presents a number of


inherent limitations and difficulties that can be addressed with design patterns.
Singleton and other creational patterns control the controlled creation of objects and
guarantee a single instance when required. Tree-like structures can be made simpler
24
HND-50 Toe Yuya San
by using structural patterns like Composite, which provide for the uniform treatment
of individual objects and compositions. Behavioral patterns such as Chain of
Responsibility allow tasks to be assigned to different objects, which simplifies the
processing of requests and procedures.

Design Pattern in Object-Oriented Programming

An essential part of object-oriented programming is the design pattern. It is


a software infrastructure that addresses a technical issue and consists of a limited
number of classes.

Reason for using Design Pattern in OOP

It is clear that design patterns are helpful in software development. Design


patterns can greatly accelerate the development process by offering tried-and-true
solutions to typical problems. This saves time and effort because it eliminates the
need to come up with new solutions for problems that keep coming up. They provide
standardized methods that improve the readability and maintainability of code,
facilitating developer comprehension and teamwork on a codebase.

The use of design patterns is especially helpful when switching from an


analysis model to a development model. They provide practical answers for a range
of situations, such as overseeing payroll systems in which salary adjustments must
be coordinated with other system components. Design patterns help developers
adopt efficient solutions by recording best practices and lessons learned from
previous projects.

The uniformity that design patterns offer enhances the readability and
maintainability of code. They aid developers in producing more readable,
understandable code, which promotes teamwork. Additionally, since many common

25
HND-50 Toe Yuya San
problems have already been solved using design patterns, using them often results
in less code and eliminates the need to start from scratch.

Additionally, design patterns act as a cohesive communication tool for various


teams and disciplines. They serve as a common language for developers, designers,
business analysts, UX specialists, and testers, facilitating effective communication
and a standard approach to problem-solving. The effectiveness of the development
process and the final product both benefit from this shared understanding.

In conclusion, design patterns offer an organized and productive method for


developing software, encouraging readability, maintainability, and productive
teamwork. Their time- and effort-saving, tried-and-true paradigms are
indispensable resources for contemporary software development. (Team., 2023)

Analysis report on design patterns

Creational Patterns

Creational patterns, as the name implies, are closely related to the creation
of objects. These patterns are intended to be used when creating new classes. The
software design may become more complex or even have design flaws if the
necessary objects are created in the traditional format. By regulating the creation
of objects, creational design patterns provide a solution to this issue.

When instances of several distinct classes are available, creational patterns


become especially helpful. More specifically, if you use polymorphism in your

26
HND-50 Toe Yuya San
software and have to choose between different classes during runtime instead of
compilation.

A few examples of creational design patterns are the Factory Method, Object
Pool, Prototype, Abstract Factory, and Singleton.

• Abstract factory - Creates instances of multiple class families using the


abstract factory.
• Builder - Distinguishes the representations of an object from its construction.
• Manufacturing Method-> Creates several derived classes in an instance.
• Object Pool - When a class's initialization costs are high, the Object Pool is
used.
• Prototype - When creating an object takes a lot of time and money, a
prototype is used. Objects are created from the actual existing object.
• Singleton - Beneficial in situations where a single object is able to organize
actions throughout the system.

27
HND-50 Toe Yuya San

In this illustration, get_instance() is declared as static, allowing it to be called


without requiring the class to be created. A singleton object is created on the first
call to get_instance(), and it returns the same object on subsequent calls.

Structural Patterns

When building larger structures from smaller, individual parts that are
generally of different classes, structural patterns can be helpful. Because these
patterns identify a fundamental technique for identifying relationships among
entities, they can also be used to simplify the design. The basic goal of applying
structural patterns is to improve the software's functionality for the classes that are
a part of it without significantly altering its basic structure.

These structural pattern types are:

28
HND-50 Toe Yuya San

Adapter - Helps match different classes' interfaces.

Bridge - To establish a clear division between the interface and its implementation,
the Bridge design pattern is employed.

Composite - useful for organizing simple and composite objects into a proper tree-
like structure. This is beneficial because it allows you to depict the software design
using hierarchies, with each node in the tree structure having the ability to carry
out a particular function.

Decorator - This pattern aids in dynamically adding accountability to objects.

Façade - By giving the client an interface and concealing the intricacies of the
system, the facade design pattern keeps a cover on.

Flyweight- By sharing object properties, this pattern essentially reduces memory


usage.

Private Class Data - Access to private class data is restricted for mutators and
accessors.

Proxy - In this design pattern, objects stand in for other objects. For example, a
college student can provide an attendance report for another student.

We now have arithmetic expressions,


which is a very basic example of the
structural design pattern. These design
patterns are composites. How? Arithmetic
expressions consist of operators (- * /) and
operands. This operand can be an
additional arithmetic expression or just a
number. We can state that the arithmetic
29
HND-50 Toe Yuya San
expression (1 + 8) * (6 / 2) has a tree-like structure to represent it. As we can see
from the diagram below, some of the nodes carry out arithmetic operations like
addition, multiplication, and division. The fundamental hierarchy of an arithmetic
expression is also depicted in this diagram.

Behavioral patterns

Design patterns that characterize and identify how various objects interact
with one another are known as behavioral patterns. By utilizing behavioral design
patterns, complex software design flowcharts can be simplified to show the
relationships between different class objects.

Several of the patterns of behavior include:

Chain of responsibility - A method for transferring a request between a chain of


objects is called "chain of responsibility."

Command - Data-driven behavioral pattern known as a "command" contains all the


necessary information to carry out an action or to set off an event at a later date.

Interpreter - We can add linguistic components to programs by using this design


pattern.

Iterator - This pattern is used to obtain a way to sequentially access a collection


object's constituent parts without needing to understand its basic representation.

Mediator - Facilitates the exchange of information between objects.

Memento - Restores and records the internal states of objects.

Null Object - The goal of this design pattern is to produce a null object that
represents an object's absence.

Observer - This design pattern notifies several classes of change.

30
HND-50 Toe Yuya San
State - When an object's behavior varies according to its internal state, the state
design pattern is applied.

Strategy - The policy pattern, also referred to as the strategy design pattern, aids
in the runtime algorithm selection.

Template Method - The Template Method allows subclasses to override specific


steps in an algorithm without altering the algorithm's overall structure. The name
of the method implies that it defines an algorithm's framework within the superclass.

Visitor - An algorithm and the object structure it operates on are separated by this
design pattern. In essence, it leads to no modifications other than the addition of
new operations to the current classes.

Consider the "Command"


design pattern as an example. After
dining at a dinner, you make the
payment. An illustration of the
command design pattern is the
dinner order you place. How? After
you place an order, your waiter or
waitress receives your order—you
could even say, a "command"—from you. After that, they write the order on the
check to "encapsulate" it. The cook is put in a queue for your order. The diagram
below shows an example of the command design pattern, which is represented by
this "command" chain. (Mathur, 2024)

31
HND-50 Toe Yuya San

Evaluating Solid Principles and their impact on Objected


Oriented application development

Clean, maintainable, and scalable code is produced when SOLID principles are
applied, greatly improving the object-oriented application development process.

Improved maintainability is made possible by the Single Responsibility


Principle (SRP), which limits the number of specific tasks that each class performs,
making it easier to debug and localize changes. Because classes follow this principle,
testing is made easier and more readable because of the classes' concentrated and
predictable behavior. However assigning the right tasks to each class can take time,
and having more small classes could make the project more complicated.

The Open/Closed Principle (OCP) lowers the risk of regression by enabling


the addition of new features through class extensions without changing the existing
code, increasing flexibility and scalability. However, creating extensible systems
necessitates thoughtful planning and may result in over-engineering.

The Liskov Substitution Principle (LSP) ensures that subclasses can


replace their parent classes without changing system behavior, which improves code
reusability and reliability while supporting strong inheritance hierarchies and
polymorphism. One of the difficulties is making sure the subclass is implemented
correctly to prevent runtime errors.

The Interface Segregation Principle (ISP), which promotes simpler, more


focused interfaces that are easier to use and comprehend, lowers complexity and
increases modularity. This principle isolates modifications to particular interfaces,
32
HND-50 Toe Yuya San
which further increases system flexibility. However, careful planning and design
work are required to manage multiple small interfaces.

The Dependency Inversion Principle (DIP) is a last technique that


improves modularity and maintainability by increasing decoupling and making sure
that high-level modules are independent of low-level implementations. This principle
makes it easier to switch between different implementations, which enhances
testability and encourages reusability. Appropriate abstraction design can be difficult
and may add more complexity, necessitating a large amount of initial work. Overall,
even though adhering to SOLID principles presents some initial challenges, the long-
term advantages in terms of code quality, flexibility, and maintainability greatly
exceed these challenges, leading to software systems that are more resilient and
adaptive.

UML class diagram of SOLID Principles

S - Single-responsibility Principle (SRP)

A class should only have one duty or purpose, which implies that it should
have one reason to change.

UML class diagram

SRP is demonstrated in the UML by making sure every class has a unique,
single responsibility. This is an example of a basic class diagram that complies with
SRP:

33
HND-50 Toe Yuya San

Code example

The `User` class in the given Dart code encapsulates basic user data and
provides methods to access attributes. It represents a user entity with attributes
{name} and {email}. It adheres to the Single Responsibility Principle by
concentrating only on user data management. With a `saveUser` method to store
user data, the `UserStorage` class manages the task of storing `User` objects.
Code maintainability and flexibility are improved by this separation, which
guarantees that each class has a specific role: `User` manages user data, while

34
HND-50 Toe Yuya San
`UserStorage` manages data storage. As the application grows, this adherence to
SRP encourages easier scalability and clearer code organization.

O - Open-closed Principle (OCP)

Classes, modules, functions, and other software entities need to be closed for
modification but open for extension.

UML class diagram

Use interfaces or inheritance to extend functionality without changing the existing


code to demonstrate OCP.

Code example

35
HND-50 Toe Yuya San

The Shape abstract class in the provided Dart code defines an abstract area()
method that makes sure every subclass implements its own area calculation. While
the Rectangle subclass determines its area based on width and height, the Circle
subclass extends Shape and determines its area based on the radius. By
encouraging code reuse, preserving flexibility, and enabling the addition of new
shapes without altering already-written Shape code, this configuration complies with
the Open/Closed Principle of SOLID principles. This design uses inheritance and
polymorphism to bring shape-related operations under a single interface, ensuring
that each shape type encapsulates its unique behavior.

L - Liskov Substitution Principle (LSP)

Subtypes must be able to be substituted for their base types without affecting
the program's correctness.

UML Class Diagram

Subclasses that can take the place of the base class without affecting functionality
are used as an example of LSP.

36
HND-50 Toe Yuya San

Code example

The `Bird` abstract class in the Dart code provided acts as a template for
different kinds of birds, specifying a standard behavior with the `fly()` method that
subclasses need to implement. A sparrow-specific concrete implementation of
`fly()` is provided by the `Sparrow` class, which is an extension of `Bird`. By
guaranteeing that every subclass (including hypothetical future subclasses like
{Eagle} or {Penguin}) can seamlessly substitute their base class ({Bird}) without
affecting the program's correctness, this setup serves as an example of the Liskov
Substitution Principle (LSP) of the SOLID principles. The `fly()` behavior can be
expanded by any subclass while still being compatible with the `Bird` interface,
allowing for more code flexibility and scalability in the application's bird-related
features.

I - Interface Segregation Principle (ISP)

It is not appropriate to make clients rely on interfaces they do not use. In other
words, a class should only implement the methods that it finds useful.

37
HND-50 Toe Yuya San
UML class diagram

Split large interfaces into smaller, more focused interfaces to demonstrate ISP.

Code example

38
HND-50 Toe Yuya San

Classes implementing the Workable and Eatable abstract classes are required
to follow the specific behaviors defined by their work() and eat() methods,
respectively. Workable is implemented by the Robot class, which offers a customized
version of the work() method for tasks pertaining to robots. The Interface
Segregation Principle (ISP) of the SOLID principles, on the other hand, is
demonstrated by the Human class, which implements both Workable and Eatable
and makes sure that classes only rely on interfaces that are relevant to them. This
design ensures that each class has a minimal and well-defined set of responsibilities
and promotes code cohesion by allowing the Robot and Human classes to
independently define and execute their respective functionalities (eat() and work()).

D - Dependency Inversion Principle

39
HND-50 Toe Yuya San
Modules at higher levels shouldn't rely on modules at lower levels.
Abstractions should be the basis for both. Details shouldn't influence abstractions.
Abstractions should drive details.

UML class diagram

Introduce abstractions (interfaces or abstract classes) that are necessary for both
high-level and low-level modules to function in order to demonstrate DIP.

Code example

40
HND-50 Toe Yuya San

Concrete implementations of the `Service` abstract class are required to fulfill


a contract with a single method, `operation()`, as defined by the Dart code
provided. By offering a particular implementation of `operation()`, the
`ConcreteService` class implements `Service`. By relying on the `Service`
abstraction rather than on particular implementations, the `Client` class illustrates
the Dependency Inversion Principle (DIP) of the SOLID principles and encapsulates
a `Service} instance. This promotes flexibility and ease of maintenance by keeping
the `Client` class independent of the specifics of `operation()` implementation in
`ConcreteService`. `doWork()` is called to carry out the `operation()` specified by
the `Service} interface, after a `Client` object receives an instance of
`ConcreteService` that was created in the `main()` function. This illustrates how
DIP enables interchangeable components in the application architecture.

UML class diagram of Design Patterns

Class diagrams, which physically represent a system's classes, attributes,


operations, and relationships between objects, are essential to comprehending
design patterns.

41
HND-50 Toe Yuya San

Creational Design Patterns

Singleton pattern

A class is ensured to have a single instance according to the Singleton pattern,


which also offers a global point of access to it.

UML class diagram

Code example

42
HND-50 Toe Yuya San
To make sure that there can only be one instance of the class, the Singleton
class is implemented. This is accomplished by initializing a static final instance
(_instance) upon class loading and utilizing a private named constructor
(Singleton._internal()). This one instance can be accessed globally through the
getter method instance. By printing a message, the doSomething method shows
how the Singleton instance works. The Singleton pattern's goal of offering a single,
consistent instance throughout the application is demonstrated in the main function
by calling the Singleton instance's doSomething method and accessing it through
the Singleton.instance getter.

Factory Method Pattern

Although the Factory Method pattern specifies an interface for object creation,
subclasses are free to modify the kind of objects that are generated.

UML class diagram

Code example

43
HND-50 Toe Yuya San

We use the Factory Method design pattern in this Dart code to generate
various products via a shared interface. All concrete products must implement the
`doStuff` method, which is defined by the `Product` abstract class. Concrete
classes {ConcreteProductA} and `ConcreteProductB} implement `Product` and
give `doStuff` particular behaviors. The `Creator` abstract class contains the
method `someOperation} that utilizes the product produced by `factoryMethod` to
carry out an operation, as well as the `factoryMethod` that is in charge of creating
`Product` objects. The subclasses {ConcreteCreatorA} and `ConcreteCreatorB} of
`Creator} return instances of `ConcreteProductA} and {ConcreteProductB},

44
HND-50 Toe Yuya San
respectively, by overriding `factoryMethod}. `ConcreteCreatorA} and
`ConcreteCreatorB} instances are created and their `someOperation` method is
called in the `main} function, illustrating how the Factory Method pattern enables
the creation of various products through a consistent interface. The Open/Closed
Principle is upheld by this method, which encourages loose coupling and permits the
addition of new product types without changing the existing code.

Structural Design Patterns

Adapter Pattern
By converting a class's interface into a different interface that the client
expects, the adapter pattern makes it possible for incompatible interfaces to exist
together.

UML class diagram

Code example

45
HND-50 Toe Yuya San

It is shown that the Adapter design pattern enables the coexistence of


incompatible interfaces. A request method defined by the Target class symbolizes
the common interface that the client expects. In contrast, the Adaptee class features
a uniqueRequest method that behaves in a way that is incompatible with the Target
interface. The Adapter class, which inherits from Target and contains an instance of
Adaptee, is introduced to fill this void. In order to call the specificRequest method
of the Adaptee instance and modify its behavior to conform to the expected
interface, the Adapter class overrides the request method. An instance of Adaptee
is created and passed to the Adapter instance in the main function. The Adapter
pattern enables the client to use the Adaptee through the Target interface without
changing the pre-existing classes; this is demonstrated by calling
adaptee.specificRequest() internally when adapter.request() is called. When
integrating new systems or components with legacy ones, this pattern can be
helpful.

Decorator Pattern

46
HND-50 Toe Yuya San
Individual objects can have behavior added to them statically or dynamically
using the decorator pattern, all without affecting the behavior of other objects in the
same class.

UML class diagram

Code example

47
HND-50 Toe Yuya San

The Decorator design pattern, which enables behavior to be added to


individual objects dynamically without affecting the behavior of other objects from
the same class, is demonstrated in this Dart code. The `operation` method, which
needs to be implemented by every concrete component, is defined by the
`Component} abstract class. A class called `ConcreteComponent` offers a basic
implementation of the `operation} method in addition to implementing
`Component`. By taking another `Component` as a parameter, the `Decorator`
class, which also implements `Component`, overrides the `operation` method to
assign the call to the wrapped component. Concrete decorators
{ConcreteDecoratorA} and `ConcreteDecoratorB} add their own behavior to
`Decorator} by changing the output of the `operation} method. Layers of behavior
are added by creating an instance of {ConcreteComponent} and wrapping it with
`ConcreteDecoratorA} and `ConcreteDecoratorB} sequentially in the `main`
function. The finished product demonstrates how the decorators expanded the
functionality of the original component and highlights how the Decorator pattern can
be used to transparently and dynamically improve or modify behaviors.

Behavioral Design Patterns

Observer Pattern

By defining a one-to-many dependency between objects, the observer pattern


enables automatic notification and updating of all dependents when an object
changes state.

48
HND-50 Toe Yuya San
UML class diagram

Code example

49
HND-50 Toe Yuya San

We demonstrate the Observer design pattern, which enables an object


(referred to as the subject) to broadcast changes in its state to a list of dependent
objects (referred to as observers). The update method that concretes observers
need to implement is specified in the Observer abstract class. A concrete
50
HND-50 Toe Yuya San
implementation of the update method, which prints the updated state, is provided
by the ConcreteObserver class, which is an implementation of Observer. A state and
a list of observers are kept up to date by the Subject class. In addition to methods
for attaching and releasing observers, it offers a notify method that notifies all
attached observers when a state change occurs. The notify function is used to notify
all observers of the new state after the setState method sets the subject's state.
Two ConcreteObserver instances and a Subject instance are created in the main
function. The subject's state is changed twice while the observers are attached to
it, showing how the observers are informed when the subject's state changes.
Systems for distributed event handling can be implemented with the help of this
pattern.

Strategy Pattern

The Strategy pattern encapsulates, defines, and renders compatible a family


of algorithms. Strategy allows the algorithm to change without depending on the
clients using it.

UML class diagram

51
HND-50 Toe Yuya San

Code example

52
HND-50 Toe Yuya San

The Strategy design pattern, which defines a family of algorithms,


encapsulates each one, and makes them interchangeable, is demonstrated in this
Dart code. The `algorithm’ method is declared in the `Strategy’ abstract class and
is implemented by the concrete strategies ‘ConcreteStrategyA’ and
`ConcreteStrategyB’, each of which offers a distinct algorithm. By using the
`setStrategy` method, the `Context` class enables dynamic strategy setting by
holding a reference to a `Strategy`. The `algorithm` method of the currently
configured strategy is called by the `executeStrategy` method. Using an initial

53
HND-50 Toe Yuya San
strategy of ‘ConcreteStrategyA’, a `Context’ instance is created in the `main’
function. Its `executeStrategy` method is then called, printing "Algorithm A". Then,
using `setStrategy’, the strategy is modified to `ConcreteStrategyB’, and
`executeStrategy` is called once more, displaying "Algorithm B". This pattern
facilitates reuse and flexibility by enabling dynamic runtime changes to the context's
behavior without altering the code of the context.

Class diagram of given code scenario including multiple design


patterns

Singleton Patterns

54
HND-50 Toe Yuya San
The Singleton design pattern, which ensures a class has only one instance and
offers a global point of access to it, is best illustrated by the Library class. In this
instance of implementation:

Static Instance: The class starts with a single instance of Library and keeps a private
static instance of itself.

Private Constructor: Because Library._internal() is a private constructor, external


classes cannot instantiate Library objects directly.

Factory Method: To guarantee uniform access to the single instance throughout the
application, the factory Library() method returns the singleton instance _instance.

Book Management: It maintains an internal list of Books and notifies registered


LibraryObserver objects of any changes by using methods like addBook() and
removeBook().

Observer Pattern: Makes use of the Observer pattern by keeping track of observers
(observers) who receive notifications via _notifyObservers() whenever a book is
added or removed.

Because of the way the application is designed, all components share a single
instance of Library, which makes it easier to manage books centrally and enables
observers to respond to changes in the library's status.

Factory Method Pattern

55
HND-50 Toe Yuya San

The Dart code shows how to create different kinds of books (textbook and
novel) from an abstract Book class by using the inheritance hierarchy and Factory
Method pattern.

Abstract Book Class: All concrete book types inherit this abstract base class, which
defines common methods (getTitle(), getAuthor(), and getISBN()) and common
attributes (title, author, and isbn). This follows the guidelines of object-oriented
programming and encourages the reuse of code.

Textbook and Novel are Concrete Book Classes that extend the Book class by
extending its constructor to initialize particular attributes (title, author, isbn) using
the super keyword. This specialization enables unique characteristics and behavior
suited to various book genres.

BookFactory: The creation logic for various book kinds (textbooks and novels) is
contained in the BookFactory class. Based on a given type parameter, it dynamically
instantiates and returns the appropriate subclass using the createBook() method.
This centralizes the creation process and decouples client code from the details of
object creation, improving scalability and flexibility.

Adapter Pattern

56
HND-50 Toe Yuya San

The Adapter design pattern, which is used to make incompatible interfaces


work together, is demonstrated in the Dart code that is provided. The Book class is
specifically modified by the BookAdapter class to conform to the CatalogItem
interface.

The CatalogItem class serves as a target interface and has three methods that
return empty strings: getTitle(), getAuthor(), and getISBN(). The contract that
clients expect is defined by this interface.

BookAdapter Class: A class that extends CatalogItem and modifies a Book instance
to comply with the CatalogItem specification. In order to return the relevant
properties from the Book instance, it implements the getTitle(), getAuthor(), and
getISBN() methods and contains a Book object. This makes it possible to use Book
objects instead of the original Book class in situations where CatalogItem instances
are anticipated.

57
HND-50 Toe Yuya San
Decorator Pattern

By adding more functionality to an already-


existing Book object, the BorrowableBook class in
the provided Dart code implements the Decorator
design pattern. By adding the ability to borrow, the
BorrowableBook class extends the functionality of a Book and implements the
CatalogItem interface, enabling it to be used interchangeably with other
CatalogItem objects.

BorrowableBook Class: This class adds functionality to track the book's borrower
and accepts an instance of Book as a parameter. By assigning these calls to the
encapsulated Book instance, it implements the CatalogItem interface and provides
implementations for getTitle(), getAuthor(), and getISBN(). It also introduces two
methods: returnBook(), which resets the borrower attribute, and borrowBook(),
which sets the borrower attribute to the borrower's name that is provided. With the
help of this extension, a Book can have borrowing capabilities "decorated" without
changing the original Book class.
58
HND-50 Toe Yuya San
Observer Pattern

The Observer design pattern, which enables an


object (subject) to inform other objects (observers)
about changes in its state, is illustrated in the Dart
code provided. Using this pattern to implement distributed event-handling systems
is very helpful. The abstract base class (interface) in this case that specifies a
procedure for getting update notifications is called LibraryObserver. Two concrete
implementations of this interface, BookAddedObserver and BookRemovedObserver,
each provide particular behavior in response to an update.

The LibraryObserver class is an abstract class that specifies the update method that
all concrete observers need to implement. By enforcing a common interface, this
design enables uniform notification of changes to all observers.

BookAddedObserver Class: This class implements the update method of the


LibraryObserver interface, which prints a message to the user whenever a new book
is added to the library. This class captures the actions that take place when a new
book is added.

Similar to the LibraryObserver interface, the BookRemovedObserver class prints a


notification when a book is taken out of the library. The actions that follow the
removal of a book are captured in this class.

59
HND-50 Toe Yuya San
Strategy Pattern

The Strategy design pattern, which defines a family of algorithms,


encapsulates each one, and renders them interchangeable, is illustrated by the Dart
code that is provided. The algorithm can change without affecting the clients that
use it thanks to this pattern. In this instance, a standard interface for various search
algorithms is defined by the SearchStrategy abstract class. Concrete
implementations of this interface include TitleSearch and AuthorSearch, each of
which implements a unique search algorithm.

The SearchStrategy class is an abstract class that defines a search method that
accepts a query string and a list of Book objects as parameters. This class allows for
interchangeability and flexibility by defining the common interface for all search
strategies.

TitleSearch Class: Provides a tangible search method implementation in order to


implement the SearchStrategy interface. The book whose title matches the query is
returned by this method, which iterates through the list of books. It is a case-
insensitive comparison.

AuthorSearch Class implements the SearchStrategy interface by offering a practical


search method implementation. The book whose author matches the query is
60
HND-50 Toe Yuya San
returned by this method, which iterates through the list of books. It is also a case-
insensitive comparison.

Code by using SOLID principles with design pattern

61
HND-50 Toe Yuya San

This diagram is part of my code.

Data Services Interface

Different data service strategies can be implemented thanks to the


DataService interface, which defines a contract for data operations. By following the
Open/Closed Principle, this abstraction ensures that different data services can be
developed and integrated seamlessly.

62
HND-50 Toe Yuya San
FirebaseDataService Class

In order to communicate with Firebase for data operations, the


FirebaseDataService class implements the DataService interface. This
implementation follows the Single Responsibility Principle by encapsulating
Firebase-specific logic.

Register Class

The application's main entry point, the Register class, configures the
CarForm's theme and navigation. In order to ensure an organized application
structure, this class is in charge of configuring the initial state and routing.

CarForm Class

The stateful widget known as the CarForm class controls the inputs and
interactions of the car form. It respects the principle of single responsibility and
encourages clear separation of concerns by managing state and user input.

uploadData Method

The uploadData method uses the DataService to upload the data after
gathering it from the form fields. It makes sure users are aware of the operation's
success by using Fluttertoast to provide user feedback. The focused responsibility
of this method improves maintainability and clarity.

_buildTextField Method

A text field widget is created using the _buildTextField method, which also
takes a label and controller as input. This builder pattern-compliant encapsulation
of widget creation encourages modularity and reuse.

_buildButton Method

A styled button with the supplied text, a onPressed callback, and an optional
width is created by the _buildButton method. This approach improves the modularity
and maintainability of the code by encapsulating the creation of buttons.

63
HND-50 Toe Yuya San
_buildButtonRow Method

The _buildButtonRow function sets up a row of buttons, each of which can be


used to add, view, search for, and update data, among other specific actions. By
using clean coding principles, this method arranges the UI layout in a modular and
reusable fashion.

Single Responsibility Principle (SRP)

Every function and class have a single function.

Register class: In responsible of building the navigation and main application


structure.

CarForm class: Defines UI interactions and the state of the car form.

FirebaseDataService class: Manages Firebase-related data operations.

Open/Closed Principle (OCP)

Although they can be extended, classes cannot be changed.

New implementations can be made of the DataService interface without changing


the existing code.

FirebaseDataService is an extendable and replaceable implementation of


DataService.

Liskov Substitution Principle (LSP)

Derived classes should be substitutable for their base classes.

64
HND-50 Toe Yuya San
Following the same interface, FirebaseDataService can be used anywhere
DataService is expected.

Interface Segregation Principle (ISP)

It is not appropriate to make clients rely on techniques they do not employ.

Just the essential methods for data operations are provided by the narrow and
uncomplicated DataService interface.

Dependency Inversion Principle (DIP)

CarForm depends on the abstract DataService, which makes testing easier


and flexible.

Design Patterns

Factory Pattern

The Factory Pattern can be applied easily because of the DataService interface's
abstraction, even though it isn't implemented explicitly. This design pattern
encourages flexibility and scalability by making it easier to create and inject various
data service implementations as needed.

Dependency Injection

The Dependency Injection pattern is shown by the CarForm class, which uses its
constructor to obtain an instance of DataService. By separating the class from
particular data service implementations, this method improves testability and makes
switching between implementations simple.

65
HND-50 Toe Yuya San

Builder Pattern

The UI widget creation process is contained in the methods _buildTextField and


_buildButton. Because of this modular strategy, which is in line with the Builder
Pattern, the UI construction process is more structured and reusable. The code
encourages separation of concerns and clarity by encapsulating the creation of
widgets.

Clean Coding Method

Meaningful Names

The code illustrates how variables, functions, and classes are named meaningfully,
improving readability and maintainability. For instance, the class CarForm, the
variables modelController, and uploadData have descriptive names that make it
obvious what they do and how they work.

Functions Should Do One Thing

Following the principle that a function should only be in charge of one task, every
method in the code focuses on a single functionality. For example, the uploadData
method's exclusive purpose is to manage data upload and give the user feedback,
guaranteeing the code's design clarity and simplicity.

Minimize Procedures

Small, targeted methods are maintained throughout the code; _buildTextField and
_buildButton are two examples. These techniques are clear and focused on
producing particular user interface elements, which encourages modularity and
readability.
66
HND-50 Toe Yuya San

Consistent Formatting

Throughout the code, standard naming conventions, spacing, and indentation are
used. This formatting consistency makes work easier to collaborate on and maintain,
in addition to making the text easier to read.

Error Handling

The code has appropriate error-handling components. For example, Fluttertoast is


used to inform the user whether data operations were successful or unsuccessful.
This improves the user experience by guaranteeing that users are aware of the
status of the application.

UML class diagram of my application

67
HND-50 Toe Yuya San
The structure of a mobile application aimed to manage BMW vehicle
information is shown in this UML class diagram. The diagram shows the interactions
between the various app components.

The structure and relationships between different classes in a Flutter


application likely used for organizing and displaying data related to cars are depicted
in the provided UML class diagram. Along with the state management and data
service classes, it contains subclasses of both StatelessWidget and StatefulWidget
that represent various UI components.

Main Components and Their Relationships

• MyApp, CarList, Register (StatelessWidget subclasses)


o Since these classes extend StatelessWidget, their user interface remains
unchanged beyond the initial build. Every class has a build method that
yields a Widget.

• Searchdata (StatelessWidget subclass)


o It is a different subclass of StatelessWidget and has the build method
for its user interface. This class probably manages the app's search
feature.

• StatefulWidget and State Relationship


o A base class for widgets with state-changing capabilities is called
StatefulWidget. CarForm, Updatedata, and LoginScreen are subclasses
of StatefulWidget in this diagram.
o A State class corresponds to each StatefulWidget and is responsible for
managing its state. _CarFormState, _FormState, and
_LoginScreenState are the state classes represented in the diagram.

68
HND-50 Toe Yuya San

• _CarFormState (State subclass)


o Manages the CarForm widget's state. To manage text input fields, it has
multiple TextEditingController instances (modelController,
nameController, priceController, categoryController, yearController). It
contains the following methods: uploadData, _buildTextField,
_buildButtonRow, _buildButton; these are used for building user
interface elements.

• _FormState (State subclass)


o Controls the state for a different section of the form. It contains
instances of TextEditingController for string fields (model, name, price,
category, year, id) and various fields (nameController). It offers two
ways to search for and remove cars: searchCar and deleteCar.

• _LoginScreenState (State subclass)


o Manages the LoginScreen widget's state. It has instances of
TextEditingController for managing password and email input fields. The
functionality for login is handled by the _login method.

• DataService and FirebaseDataService


o The addData method of the DataService class is used to add data. Being
a subclass of DataService, FirebaseDataService offers a particular
implementation for adding data to Firebase.

• CarForm and DataService Relationship

69
HND-50 Toe Yuya San
CarForm relies on DataService for data operations; this is indicated by
the dependency injection attribute dataService of type DataService in
the CarForm class. An instance of _CarFormState is returned by the
createState function, connecting the StatefulWidget to its state class.

This UML class diagram clearly shows the difference between StatelessWidget and
StatefulWidget, demonstrating an organized method for developing a Flutter
application. The diagram also shows how data operations are abstracted using
service classes and how state is managed independently from the UI components
using State subclasses. Because of the design's emphasis on modularity, the code
is simpler to maintain and expand. The foundation of this application's functionality
is the use of TextEditingController for form inputs and methods for managing user
interactions (such as login and data upload).

UI Design Explanation

Login Page

70
HND-50 Toe Yuya San

The logo and branding of the provided UI design suggest that it is a login
screen for a BMW-related application. Applications that need user authentication
frequently have this screen. A comprehensive overview of each element and its
function can be read below:

Logo

The BMW logo can be seen clearly in the top center of the screen. For the user, this
acts as a visual cue that shows the association with BMW right away.

The words "SHEER DRIVING PLEASURE" are shown beneath the logo, reiterating the
brand's tagline and extending a warm greeting to the user.

Form field

Email - The email address '[email protected]' is given; this is usually a text


placeholder or user-inputted data. The user's email address is entered in this field.

Password - A password is entered, usually hidden for security reasons (e.g.,


123456). The password for the user should be entered in this field.

Login button

71
HND-50 Toe Yuya San
The "LOGIN" button is a blue button that appears beneath the form fields. The
user can submit their login credentials by clicking this button. It starts the
authentication procedure when clicked.

Forget password link

There is a link labeled "Forgot Password?" below the login button. In the event that
users forget their password, they can get it by clicking on this link. Usually, it starts
a recovery process or reroutes the user to a password recovery screen.

Register Page

Section Header

There is a back navigation arrow on the left side of the top section.

The BMW logo in the center most likely indicates the brand connected to this car
inventory app.

72
HND-50 Toe Yuya San

Input field

Subordinate to the header are four input fields:

"Enter Model" allows users to enter the model of the car, such as "BMW X5".

"Enter Name" allows the user to enter the name of the car (BMW)

"Enter Purchase Price (USD)" allows users to enter the car's purchase price in US
dollars.

"Enter Category": This field probably lets users choose the type of car they want
(sedan, SUV, etc.).

"Enter Year of Manufacture": This field allows users to enter the year that the car
was produced.

Action button

Four buttons that are horizontally aligned are located at the bottom of the interface:

"Add Car": Probably used to add a fresh vehicle to the stock.

"Show Available Vehicles" – Most likely presents a list of available vehicles.

"Search": Enables users to look for particular cars according to criteria.

"Update"- Probably used to update data regarding cars that are currently on the
road.

List of Car Page

73
HND-50 Toe Yuya San

This page is simple.

Title and Navigation

The title "Available Cars" is displayed in the upper section.

An arrow pointing left most likely points to the previous page's navigation or back
button.

Car list

Several BMW car models are listed in the main content area.

Every entry consists of

Model name, such as "BMW001" or "BMW0006."

The car's year (for example, "2003," "2007").

The price expressed in Myanmar Kyat (MMK) is "$2500.00," "MMK 4875000.00,"


etc.

74
HND-50 Toe Yuya San
Search Data

Title and navigation

There is a back navigation arrow on the left at the top.

It says "Search Car Model" in the title.

Search input field

There's a text input field beneath the title with the placeholder text "Enter Model."
Users have the option to search for a specific car model by typing its name.

Action button

There are two buttons positioned next to one another:

"Search"- Clicking it is probably going to start a search for the car model you
entered.

"Delete"- Using this button will either erase any previous search results or clear the
input field.
75
HND-50 Toe Yuya San

Car Model Information Display

Information about a car model that is searched in above field is shown in an outlined
box:

"Model" - Displays the particular vehicle model, such as "BMW X5".

"Name"- Identifies the model's name (such as "BMW Convertible").

"Price"- Shows the cost, such as "65000 USD."

"Category" - Indicates the type of object (e.g., "Convertible").

"Year" - Displays the year of manufacture (for example, "1999").

Update Page

Navigation bar

76
HND-50 Toe Yuya San
The top of the screen is where the navigation bar is located. There are two icons in
it.

Left Back Arrow: This icon probably enables users to return to a previous step or
screen.

Users can perform related actions or edit settings by tapping the Edit Icon (Right).

Input field

Two input fields are available for user interaction: "Search Car Model" allows users
to enter the name of a particular car model they're looking for.

The field labeled "Enter New Price (USD)" enables users to enter a new car price in
US dollars.

Buttons

Below the input fields are two buttons arranged horizontally.

The "Search" button, when clicked, probably starts a search based on the car model
that was entered.

"Update" Button: This button most likely uses the value entered in the second input
field to update the price of the car.

Different methods of implementing automatic testing as


designed in the test plan

Unit testing

This is an examination of the system's discrete parts, or modules. It assists


you in assessing brief pieces of code and finding out how well each app's component
77
HND-50 Toe Yuya San
works. For the development process to be optimized, this kind of testing is essential.
Enhancing code quality, reducing project costs, expediting development, and
providing instant access to project documentation which is actually a collection of
unit tests are all made possible by it.

Integration testing
This kind of testing involves combining and testing different software
components. This offers a chance to check how well the new module interacts with
other parts and integrates with the shared code base.

System testing
This is an extensive test to see how well the software works as an integrated
unit. QA engineers determine how the completed application satisfies the specified
requirements by conducting various testing methods for various program modules.
(Poliarush, 2023)

The differences between developer produced and vendor


provided automatic testing tools for applications and software
systems

Developer produced tools

78
HND-50 Toe Yuya San
Katalon Studio

Katalon Studio is an
additional open-source on the
web, mobile, and API testing
suite. With features like
recording, auto-generating test
scripts, and robust integrations,
it is one of the most
comprehensive testing suites
on the list.

Even non-programmers can easily start using this testing framework because it is
robust enough to support scalability.

Extant CI/CD configurations are well-suited for Katalon Studio. For example,
integrating it with Github or Gitlab's continuous testing tools is simple. It's ideal for
Agile teams because of this.

OpenTest

Another open source program


that automates testing for desktop,
mobile, online, and API apps is
called OpenTest. Functional testing
is the main application for it.

Due to various test scenarios not


being covered yet, it still has a lot
of limitations. However, because it
writes test actions using simple English terms, it is excellent for both beginners and
non-programmers.

79
HND-50 Toe Yuya San
Keyword-driven testing, parallel testing, data-driven testing, and mobile testing
using Appium and Selenium are a few of its most notable features.

Cypress

For front-end or end-to-end


automated testing, Cypress is an
excellent tool.

A straightforward npm install


cypress or yarn add cypress
command can be used to install
Cypress in a project. Cypress test
scripts are easy to write for JavaScript writers accustomed to using unit testing tools
like Jest or Mocha.

Because tests can be grouped by browser type, environment, package type, and
other criteria, its dashboard increases testing power and speed. The parallelization
functionality makes it simple for developers to test more features and run more
tests. (Vergara, 2020)

Vendor provided tools

Gatekeeper

80
HND-50 Toe Yuya San
Large businesses that require
unrestricted storage and broad access
can use this VMS. With more than 200
contracts, Gatekeeper's cloud-based
solution provides seamless vendor
lifecycle management. In addition, it
offers e-sign capabilities, vendor
requests, and onboarding automation
options for contract approvals.

Using a Kanban Workflow Engine, this VMS enables an organization to automate


record-building and expedite data entry and SLA management. Additionally, it
provides customizable workflow creation and management options, doing away with
manual operations. This VMS offers a wide variety of integration for over 220 apps
because it is fully cloud-based. But because it offers capabilities that are specifically
designed to work with huge organizations, the cost is a touch pricey.

Cflow

The final VMS on our list is


Cflow by Cavintek. It is a powerful
cloud workflow automation solution
with a lot of features that help a
business improve procurement
performance and streamline its
procurement department.

Effective KPI tracking, the removal of process redundancies, enhanced supplier


relationship management, improved compliance management, improved visibility
features for managing the procurement process, automated follow-ups, invoice

81
HND-50 Toe Yuya San
approvals, reminders, and notifications for procurement orders, and the ability to
create customized reports are just a few of the main benefits of utilizing Cflow.

Genuity

According to reviews, Genuity works well


for IT organizations because of its many special
features and reasonable price, which make it
easy for IT workers to manage vendor
relationships. It offers IT tools with an intuitive
UI as well as tools that are specifically tailored.
Numerous systems, including AWS, Salesforce, Quickbooks, G Suite, Azure,
and others, are easily integrated with Genuity. It also facilitates effective
vendor management and the discovery of new SaaS providers. (cflowapps,
2024)

Comparison Table

Feature Developer-Produced Tools Vendor-Provided Tools


Control and Ownership Complete control and Limited control, managed
ownership by vendor
Maintenance Handled by the Managed by vendor
development team
Ease of use Requires technical User-friendly interfaces,
expertise extensive documentation
Cost Potentially cost-effective, Licensing fees,
hidden costs in subscription costs
maintenance

82
HND-50 Toe Yuya San
Updates Managed by the Regular updates from the
development team vendor

Different form of automatic testing

Integration testing

Testing every component of the application as a whole is called integration


testing. Its main objective is to assess if the system meets all of the functional
requirements that have been established for it. The process of integration testing
involves examining the interactions that arise between the various components
when they are combined.

Integration testing, which usually comes after unit testing, makes sure that
all of the functionalities work together seamlessly to provide smoothly operating
software as a whole. Integration testing can be approached in a number of ways,
including the Sandwich, Top-Down, Bottom-Up, and Big Bang techniques.

Widget testing

One widget is tested via a widget test, a component test in other UI


frameworks. A widget test aims to confirm that the widget's user interface (UI)
functions and appears as intended. It takes several classes and a test environment
that has the right widget lifecycle context to test a widget.

The tested Widget should, for instance, be able to execute layout, instantiate
child widgets, and receive and respond to user events and actions. For this reason,
a widget test is more thorough than a unit test. But a widget test uses a simplified
implementation instead of a complete UI system, just like a unit test does. (docs,
2024)
83
HND-50 Toe Yuya San

Pros of widget testing

Clear Purpose: It is evident that the test's goal is to confirm that buttons and text
fields two types of user interface elements are present in the Updatedata widget
and that their placement in the widget tree is accurate.

Use of Keys for Identification: By locating widgets using keys


(Key('search_field'), Key('price_field'), and Key('update_button')), the test is more
resilient and less likely to fail if the widget tree changes in a way that doesn't impact
these particular widgets.

Appropriate Testing Structure: The test is organized according to the Arrange-


Act-Assert pattern, which is a recommended test structure.

84
HND-50 Toe Yuya San
Cons of widget testing

Misleading Test Description

Although "Presence of email and password text fields" is mentioned in the test
description, the automobile search and price fields are the actual keys that are being
evaluated. Confusion may result from this.

Potential for False Positives

The test may fail if in the future, more widgets with the same keys (search_field,
price_field, update_button) are added to the widget tree. It is preferable to scope
keys with more precision.

Limited Scope

The test does not examine the widgets' starting values, states, or interactions—all
of which are critical components of a thorough test suite—it merely confirms the
widgets' existence.

Unit testing

Unit testing is a software testing methodology that involves evaluating each


program functions or components separately to make sure they function as
intended. Writing test cases for each tiny program unit, like a single function or
method, is part of this process to ensure that it generates the desired output for a
range of inputs. Unit testing enhances code quality, facilitates the management of
future modifications, and helps find and repair defects early in the development
process by concentrating on the smallest components of an application. In software
development, it's an essential technique that helps write dependable and
manageable code.

85
HND-50 Toe Yuya San

Pros of widget testing

Modular Function

Because the calculating logic is contained in a distinct method called calculate selling
price, the code is more reusable and simpler to test on its own.

Clear Test Structure

The test is written using the Arrange-Act-Assert pattern, which is a recommended


method for creating exams that are easy to read and comprehend.

Specific Test Case

86
HND-50 Toe Yuya San
The precise and uncomplicated test case guarantees that, given the inputs, the
selling price computation is accurate.

Readable Code

The test case and the function are both written in a clear, accessible style that
facilitates understanding of the implementation and goal by others.

Cons of unit testing

Hardcoded Expected Value

The test has the anticipated value (54600000) hardcoded. This value will need to
be updated manually, which can be error-prone if the calculation's logic changes.

Limited Test Coverage

There is only one case covered in the test. Testing a variety of scenarios, including
edge cases (such as zero or negative values), would be more reliable.

Lack of Error Handling

Potential issues, such as erroneous input strings that cannot be converted to


doubles, are not handled by the calculateSellingPrice function. A built-in error
management system would strengthen the function.

Demonstration

https://drive.google.com/file/d/13ywItJNVPlL_M4a49hdTeVt9alR3WavA/view?usp
=sharing

87
HND-50 Toe Yuya San

88
HND-50 Toe Yuya San

References
blog.codacy, 2023. What Is Clean Code? A Guide to Principles and Best Practices. [Online]
Available at: https://blog.codacy.com/what-is-clean-code
[Accessed 2 7 2024].

cflowapps, 2024. Top 5 Vendor Management Tools Every Organization Needs to Consider.
[Online]
Available at: https://www.cflowapps.com/top-vendor-management-tools/
[Accessed 9 7 2024].

docs, 2024. Testing Flutter apps. [Online]


Available at: https://docs.flutter.dev/testing/overview
[Accessed 7 11 2024].

Hadiyanto, Z., 2021. Types of Relation Between Classes in Object Oriented Programming.
[Online]
Available at: https://dev.to/fajarzuhrihadiyanto/types-of-relation-between-classes-in-
object-oriented-programming-551m
[Accessed 19 6 2024].

Herrity, K., 2023. What Is Object-Oriented Programming (OOP)? A Complete Guide.


[Online]
Available at: https://www.indeed.com/career-advice/career-development/what-is-object-
oriented-programming
[Accessed 19 6 2024].

Khan, M. H., 2023. Understanding Object-Oriented Relationships: Inheritance,


Association, Composition, and Aggregation. [Online]
Available at: https://medium.com/@humzakhalid94/understanding-object-oriented-
relationships-inheritance-association-composition-and-aggregation-4d298494ac1c
[Accessed 1 7 2024].

Mathur, T., 2024. Types of Design Patterns. [Online]


Available at: https://www.scaler.com/topics/design-patterns/types-of-design-pattern/
[Accessed 19 6 2024].

89
HND-50 Toe Yuya San
Poliarush, M., 2023. Types of Automated Testing Explained Within Test Strategy. [Online]
Available at: https://testomat.io/blog/types-of-automated-testing-explained-within-test-
strategy/
[Accessed 9 7 2024].

Team., T. R., 2023. Design pattern: what is it and why use it?. [Online]
Available at: https://ryax.tech/design-pattern-what-is-it-and-why-use-it/
[Accessed 19 6 2024].

Vergara, R., 2020. The Best Automation Testing Tools For Developers. [Online]
Available at: https://www.freecodecamp.org/news/best-automation-testing-tools-for-
developers/
[Accessed 9 july 2024].

Walia, S. O. a. A. S., 2024. SOLID: The First 5 Principles of Object Oriented Design.
[Online]
Available at: https://www.digitalocean.com/community/conceptual-articles/s-o-l-i-d-the-
first-five-principles-of-object-oriented-design
[Accessed 20 6 2024].

90

You might also like