CS603 - Software Architecture and Design
!!! Week 01 !!!
Lesson 1: 1.1. Design – What and Why
Software Application
Software application development process consist on different phases mentioned in the below figure.
Planning, analysis, design, deployment and implementation, testing and maintenance are steps
(phases) that involved in software development.
What and Why What is design?
Verb: to make or draw plans for something, for example clothes or buildings
Noun: a drawing or set of drawings showing how a building or product is to be
made and how it will work and look
Why should structures/systems need to be designed at all?
"You can use an eraser on the drafting table or a sledgehammer on the construction
site. “
                                                                          --Frank Lloyd Wright
Lesson 2: 1.2. Design – Objectives
The Software Design Process
During the design phase, software engineers apply their knowledge of:
      The problem domain (what the software is supposed to do)
      Implementation technologies (how the software will be built)
System Specification
      Acts as a blueprint for implementation
      Specifies the overall structure and organization of the code
Software Design Objectives
The goal of software design is to translate system specifications into a detailed plan for
technical implementation. A good design should:
      Meet the customer’s needs
      Be easy to implement
      Be efficient in terms of performance and resource use
      Be easily extendible for future changes or enhancements
Software Design and Architecture
Software design serves as a technical plan, guiding the architecture and implementation of
the final product.
Customer Requirements
The customer is a significant stakeholder that plays a vital role in the
correct development, successful implementation, and system utilization.
Customer requirements mean
      what customers or users required from the system
      how the system behaves
      what are the tasks need to perform by the system
      how users will interact with the system
      how the system will present the output
Domain Knowledge
Domain knowledge means the information and having expertise about
the particular environment and industry in which the developed system
will operate. For example, knowledge of the pharmaceutical industry and
telecom industry.
Domain Knowledge Expert Example
A person have knowledge of hospitalization process and its major
departments.
System Specification
A system specification can be a written document containing a detailed
description of all aspects of the system to be built before the project
commences.
Lesson 3: 1.3. Software Design – Complexity
What is poorly designed software?
Poorly designed means the designer did not spend a good amount of
time to analysis software requirements to design.
Poorly designed programs are difficult to understand and modify.
In start, adding small features to show working product to a client is very
easy but with the passage of time, software size increased that makes it
difficult to understand and make further modifications and adding more
features.
Cost of adding the i th feature to a well-designed and poorly designed
program
What is extendable design?
Change in software requirements and adding more features is very much
natural in software development and maintenance process. Well-designed
software is easy to understand and welcomes changes in requirements,
future modifications and adding new features.
Lesson 4: 1.4. Software Design – Complexity and Size
                                     The size does matter!
The larger the program, the more pronounced are the consequences of
poor design
Complexity Vs Size (Example of a Building)
The building in the below image is tall with many floors; the building may contain many offices,
commercial shops, parking areas, and apartments. Each entity (offices, shops, .etc.) have different
kind of facilities, fire exit directions, earthquake resistance, sanitary and sewerage. Due to its large
size, any addition or modification will be hard to manage and demand excellent design and
architectural skills. In contrast, a single room house is easy to manage and extend.
Complexity VS Size (Example of two different Applications)
A calculator with four functionalities, addition, subtraction, multiplication, and division, is easy to
manage, modify, or add any new functionality. While a big application, enterprise resource planning
(ERP), contains many different integrated components, it is hard to modify, manage, or add a new
feature. Because a calculator has 100 to 200 lines of code, but an ERP solution has millions of lines of
code so a single change in ERP may affect other components. You can imagine the complexity
relation with the size in the above example; the bigger the size, the bigger the complexity, while the
smaller the size, the smaller the complexity.
Lesson 5: 1.5. Types of Complexities
Types of Complexities
       Essential Complexities
       Accidental complexities
Essential Complexities (complexities that are inherent in the problem.)
You will understand Essential Complexities after reading below different descriptions of
essential complexities.
       Essential Complexity is just the nature of the beast you are trying to tame.
       Essential Complexity represents the difficulty inherent in any problem.
       Essential Complexity is Complexity inherent to the problem. It is Complexity related
        to the problem and cannot remove.
       Essential Complexity is how hard something is to do, regardless of how experienced
        you are, what tools you use or what new and flashy architecture pattern you used to
        solve the problem. Essential Complexity is Complexity inherent to the problem.
       Essential Complexity is the entanglement/combination of components/ideas in
        software necessary for solving the problem at hand. It cannot avoid.
Essential Complexities Examples
Example 1
If users need a program to do 30 things, then those 30 things are essential; you cannot simply
take out a few of them to make the software less complex. Whenever you are solving a
problem, there are just some areas of complexity that cannot be whittled down.
Example 2
Coordinating a nation’s air traffic is an inherently complex problem. Every plane’s exact
position (including altitude), speed, direction, and destination must be tracked in real-time to
prevent mid-air and runway collisions. The flight schedules of aircraft must be managed to
avoid airport congestion in a continuously changing environment—a severe change in
weather throws the entire schedule out of whack.
Accidental Complexities (/incidental complexities – complexities that are artifacts of the
solution.)
You will understand Essential Complexities after reading below different descriptions of
essential complexities.
       Accidental Complexity is Complexity not related to the problem. Ben Mosely and
        Peter Marks describe it as a “mishap.” It is Complexity from the fault of the developer
        and happens to be there.
       Accidental Complexity is the entanglement of components/ideas that is not necessary
        for solving the problem. This Complexity is accidental because someone probably
        didn’t think hard enough before unnecessarily tying things together. As a result, the
        software is harder to understand than it should be.
       Accidental Complexity grows from the things we feel we must build to mitigate
        essential Complexity.
Accidental Complexities Examples
Example 1
Accidental complexity refers to challenges that developers unintentionally make for
themselves due to trying to solve a problem. (Fortunately, this kind of complexity can also be
fixed or improved by developers.)
Example 2
Developers bring complexity while writing the program. This type of complexity is called
accidental complexity.
The total amount of complexity in a software solution is:
                       Essential Complexities + Accidental complexities
Design (An Antidote to Complexity) primary tool for managing essential and accidental
complexities in software.
How to remove accidental complexities?
Accidental complexities can be removed or reduce with the better design.
Lesson 6: 1.6. Why is Software Design Hard?
Why software design is very important to manage complexity?
One of the most important techniques for managing software complexity is to design systems so that
developers only need to face a small fraction of the overall complexity at any given time. Because
software designer provides a road map (blueprint) to the developer in which he mentions the system's
overall structure.
What is abstraction?
An abstraction is a simplified view of an entity, which omits unimportant details. The software
designer ignores the minor details attached to the problem and focused on the high-level details.
For example, a software designer designs the system's overall structure instead of working on the
minor details of the application, such as the colour of user interface forms and font styles of text.
Why software design is hard?
The fundamental problem is that designers must use current information to predict a future state that
will not come about unless their predictions are correct. The outcome of designing has to be assumed
before the means of achieving it can be explored: the designers have to work backward in time from
an assumed effect upon the world to the beginning of a chain of events that will bring the effect about.
Design is difficult because design is an abstraction of the solution which has yet to be created
Lesson 7: 1.7. Software Design: A Science or An Art?
                          What is Art?
                          Art is a diverse range of human activities involving creative imagination to
                          express technical proficiency, beauty, emotional power, or conceptual ideas.
                     What is Science?
                            Science is made up of fundamental principles, which can be taught as
                             truth.
                            A branch of knowledge or study dealing with a body of facts or truths
                             systematically arranged and showing the operation of general laws.
Lesson 8: 1.8. Software Design: A Wicked Problem
Wicked Problem:
       A problem that cannot be clearly defined until it’s already being solved
       No clear solution path; solving one part may reveal or create other problems
       Software design is a wicked problem and this imposes constraints upon the way in
        which the process of design can be organized and managed because the full
        requirements and structure only become clear as you design
Guru Expertise:
       Even experienced designers (gurus) may struggle to explain their exact process
       Their design skills come from deep experience and intuition, not just clear rules
Lesson 9: 1.9. Design Process - More Systematic and
Predictable
                             Practice Makes the Man Perfect
How to make the design process more systematic and predictable?
The design process can be made more systematic and predictable through the application of
methods, techniques and patterns, all applied according to principles and heuristics.
A question arises in our minds. How will we understand the design process? How can we apply a
design process to make better software design?
Design is a creative activity; every person has different skill levels and techniques, some have more,
and some have less. However, through continuous learning processes and practice, we can improve
our skills and techniques. The design process would be more systematic and predictable by applying
methods, techniques, and patterns according to principles and heuristics. After continues learning and
practicing, a designer will be able to get good designs. As a designer grows in this profession, he will
develop his principles, guidelines, and heuristics. You may not be able to document and express all
expertise. In the coming videos, we will learn established principles, procedures, and heuristics by
gurus.
Lesson 10: 1.10. Dealing with Software Complexity: Different Rules and
Principles
       Role of Modularity
       Hierarchical Organization
       Information Hiding
       Abstraction in dealing with software complexity
Good design doesn’t reduce the total amount of essential complexity in a solution but it will
reduce the amount of complexity that a programmer has to deal with at any one time. A good
design will manage essential complexities inherent in the problem without adding to
accidental complexities consequential to the solution.
Divide and Conquer
This topic is related to a strategy for solving a problem. If a problem is P and it is a large problem.
Suppose its size is n. Then we will divide P into smaller sub-problems P1, P2, P3……. Pk. So a big
problem has been divided into smaller sub-problems. Obtaining a solution to each smaller problem is
easy rather than solving a big problem at once. All sub-problems are solved individually. After getting
the solution to each sub-problem, combine all solutions into one big solution of the one big problem.
If the sub-problem is also big then apply the same divide and conquer strategy to divide this sub-
problem further.
Modularity (subdivide the solution into smaller easier to manage components)
The dictionary defines module as “each of a set of standardized parts or independent units that can be
used to construct a more complex structure.”
For example: ‘ships are now built in modules rather than built in a whole from the base up’.
In above figure, you can imagine that four individual modules have been
solved individually then combined all modules into one combined solution.
Hierarchical Organization / Structure (larger components may be composed of
smaller components)
A big problem is broken into smaller meaningful parts (Sub-systems) that can
be solved individually then we need to combine all these parts that depict the
solution of a big problem. But how will we know which part will be integrated
with which part? How we will know, which part will be top-level and other
parts will come as the sub-part of the top-level part. So Hierarchical
Organization provides the solution to organize each part in proper
Hierarchy/structure.
Information Hiding (hide details and complexity behind simple interfaces)
       A component encapsulates its behaviours and data, hiding the implementation details from
        other components. Modules should be designed so that information (i.e., algorithms and
        data) contained within one module is inaccessible to other modules that have no need for
        such information.
       The purpose of information hiding is to separate interface from implementation. By hiding
        the implementation details that are likely to change, encapsulation allows for flexibility in
        design. For example, a stack interface can define two public operations, push and pop, that
        are available to other parts of the program. However, its internal data organization, e.g.,
        whether to use a linked list or an array for storing stack elements, can be hidden.
Abstraction (use abstractions to suppress details in places where they are unnecessary)
Transitioning your thought process from program design to software design involves the use of
abstraction. When designing software, you think of ways to abstract away certain details. This is
typically done by grouping certain details together based on shared characteristics or purposes.
These shared characteristics or purposes are then a way to generalize your design.
For example, a programmer may think about a soccer ball, tennis ball, baseball, and softball as
distinct types of items. A software designer would generalize these items by classifying all of them as
a type of ball that share certain characteristics (e.g., they are all spheres with a center point and
radius) and purposes (e.g., they are all struck by an object).
Abstraction Hand-on-Exercise
You are required to explain and discuss
below image moderate discussion board.
Lesson 11: 1.11. Characteristics of Software Design
Deterministic Process:
          A process that gives the same output for the same input
          Software design is not deterministic
 1. Design is non-deterministic:
          Different designers may produce different designs for the same problem
          There is no single correct solution
 2. Design is Heuristic-Based:
          Uses rules-of-thumb and experience
          Relies on guidelines, not strict rules
 3. Design is Emergent:
          Evolves over time with feedback and experience
          Involves iterations and incremental improvements
 4. Design is Both a Science and an Art:
          Involves technical knowledge (science)
          Requires creativity and intuition (art)
Lesson 12: 1.12. Benefits of Good Design
        Good design reduces software complexity - making the software easier to understand
         and modify
        Rapid development
        Easier Maintenance
        Good design makes it easier to reuse code.
        •It improves software quality.
        •Good design exposes defects and makes it easier to test the software. •Complexity is
         the root cause of other problems such as security. A program that is difficult to
         understand is more likely to be vulnerable to exploits than one that is simpler
Why code reuse is important?
If you have developed a software, library, class, written an algorithm or written a function. If you
have written it well and test properly. Moreover, this functionality is used repeatedly in your software.
Its mean that you can call/copy/paste this functionality in your code. In return, your development
effort will be less, time will be saved and you can utilize your time efficiently. One more benefit of
code reuse is an enhancement in the quality. For example, a code written that tested multiple times
and used in different locations in your code will increase the quality of the software and boost the
confidence.
Software Quality in regard to Design
The concept of quality is a familiar one, although we tend to associate it with properties that arise
from the tasks of construction rather than with those of design. Asked for examples of ‘good’ quality,
many people are likely to identify such examples as well-made joints on an item of furniture, the
quality of the paintwork on an expensive car, or the texture of a woven fabric. All these are examples
of quality of construction rather than of design, yet quality in construction depends upon good design:
to achieve a high-quality product high standards are needed in both, and in order to achieve high
standards of quality in design products, one needs to seek high standards of quality in the design
process. Unfortunately, quality is a concept that can rarely be related to any absolutes, and even for
manufactured items ideas about quality usually cannot be usefully measured on any absolute scale.
The best that we can usually do is to rank items on an ordinal scale, as when we say that we believe
the construction of this coffee table is better than that of another, in terms of materials used and the
workmanship it exhibits. However, we lack any means of defining how much better the one is than
the other. When it comes to assessing design, rather than construction, the problem is, if anything,
worse. Quality in design is often associated with visual properties, as when we appraise the quality
typefaces, furniture and clothes. We associate elegance with good design, yet it offers no help in
quantifying our thinking and, even worse, is likely to have ephemeral aspects: it may be strongly
influenced by our ideas about fashion – so creating a context for quality. (As an example, a 1930s
radio set might look quite in place in a room that is furnished in 1930s style, but would be most
unsuited to a room that was furnished in the style of the 1980s.)
No matter how good the design is, in terms of proportions, efficient use of materials and ease of
construction and modification, our ideas about its quality will still be very largely influenced by the
actual construction. If it is badly assembled, then, regardless of how good its design may be, we will
not consider it to be of good quality. Equally, if the design is poor, no amount of good craftsmanship
applied to its construction will be able to disguise its fundamental failings. (The door may be well
made and may close well, but if it is positioned so that we graze our knuckles each time it is opened,
then we will still find it inconvenient to use.)
Exercise: Analyze the below image regarding code reusability and describe that what comes
to your mind
Lesson 13: 1.13. A Generic Design Process
The final design evolves from experience and feedback
Design is an iterative and incremental process where a complex system arises out of
relatively simple interactions
Design Process
       Final design evolves through experience and feedback
       Design is not done in one go—it is refined over time
Iterative and Incremental
       Design is developed in small steps (increments)
       Each step is revisited and improved (iteration)
       Complex systems come from simple interactions over time
Key Steps in the Design Process:
    1. Understand the problem (gather requirements)
    2. Create a black-box model (system specification-System specifications are typically
       represented with use cases (especially when doing OOD))
    3. Search for existing solutions (architecture/design patterns-that cover some or all of
       the software design problems identified.)
    4. Identify missing requirements
    5. Consider building prototypes
    6. Document and review the design
    7. Iterate over solution (Refactor) (Evolve the design until it meets functional
       requirements and maximizes non-functional requirements)
                                !!! Week 02 !!!
Lesson 14: 2.14. Inputs to the Design Process
User requirements and system specification (including any constraints on design and
implementation options)
Domain knowledge (For example, if it’s a healthcare application the designer will need some
knowledge of healthcare terms and concepts.)
Implementation knowledge (capabilities and limitations of eventual execution environment)
Constraint
A constraint is a decision over which you have little or no control as a designer/ architect. Your job is
just to satisfy to design the best system that you can, despite the constraints you face. Sometimes you
might be able to argue for loosening a constraint, but in most cases, you have no choice but to design
around the constraints.
Designer’s Communication Channels
A software designer may need to acquire some degree of ‘domain knowledge’ as a routine part of the
input needed for undertaking any particular design task. Below figure present, the different
communication channels (Inputs to the design process) through which the designer acquire the
information needed in the design process.
Lesson 15: 2.15. Desirable Internal Design Characteristics
Poorly designed programs are difficult to understand and modify
Ease of maintenance – Your code will be read more often then it is written.
Desirable Internal Design Characteristics:
                  Engineering is all about balancing conflicting objectives
 1. Minimal complexity
            Keep it simple
            Maybe you don’t need high levels of generality.
 2. Extensibility
                 Design for today but with an eye toward the future.
                 Note, this characteristic can be in conflict with “minimize complexity”.
 3. Loose coupling
            minimize dependencies between modules
 4. Reusability
            Reuse is a hallmark of a mature engineering discipline
 5. Portability
            works or can easily be made to work in other environments
Maintainability
As systems get larger and more costly, the need to offset this by ensuring a long
lifetime in service increases in parallel. In order to achieve this, designs must allow
for future modification.
Simplicity
A characteristic of almost all good designs, in whatever sphere of activity they are
produced, is a basic simplicity. A good design meets its objectives and has no
additional embellishments that detract from its main purpose.
Reusability Phenomenon (Reuse is a hallmark of a mature engineering
discipline)
The concept of reuse makes an explicit appearance in the definition provided by
Brown and Short, and implicit appearances in the others. Strictly, of course, reuse
is not an essential characteristic for a component, only a desirable one. If a large
system contains one or two uniquely crafted components among a set of reused
ones, then this can be considered as a quite pragmatic design decision that reduces
the detailed design problem to that of designing only a few components, rather
than a whole system
Jones says,
“Most experienced programmers have private libraries which allow them to
develop software with about 30% reused code by volume. Reusability at the
corporate level aims for 75% reused code by volume, and requires special library
and administrative support. Corporate reusable code also implies changes in
project accounting and measurement practices to give credit for reusability”
Van Snyder points out,
“We conjecture that barriers to reuse are not on the producer side, but on the
consumer side. If a software engineer, a potential consumer of standardized
software components, perceives it to be more expensive to find a component that
meets his need, and so verify, than to write one a new, a new, duplicative
component will be written. Notice we said perceives above. It doesn't matter what
the true cost of reconstruction is. Reuse has been successful for mathematical
software for two reasons: (I) It is arcane, requiring an enormous intellectual input
per line of code; and (2) there is a rich and standard nomenclature, namely
mathematics, to describe the functionality of each component. Thus, the cost to
reconstruct a component of mathematical software is high, and the cost to discover
the functionality of an existing component is low. The long tradition of
professional journals publishing and collecting algorithms, and offering them at
modest cost, and commercial concerns offering very high-quality algorithms at
somewhat higher but still modest cost, makes discovering a component that meets
one's need simpler than in many other disciplines, where it is sometimes not
possible to specify one's need precisely and tersely. These factors collaborate to
make it more attractive to reuse rather than to reinvent mathematical software.”
Parnas writes,
“Reuse is something that is far easier to say than to do. Doing it requires both
good design and very good documentation. Even when we see good design, which
is still infrequently, we won't see the components reused without good
documentation.”
[Book: The Mythical Man-Month]
Portability (works or can easily be made to work in other environments )
The system's level of independence on software and hardware platforms. Systems
developed using high-level programming languages usually have good portability.
One typical example is Java — most Java programs need only be compiled once
and can run everywhere.
Lesson 16: 2.16. What is good design?
What are Characteristics of a Good Software Design?
Six characteristics of good software design:
 1.       simplicity
 2.       coupling
 3.       cohesion
 4.       information hiding
 5.       performance
 6.       security
What is Good Design?
Good design is not just about:
          Writing efficient code
          Creating compact implementations
But more importantly, it is about ensuring the software is:
                   Maintainable
                   Understandable
                   Adaptable
                   Modular
Maintainable Design
A maintainable design:
      Minimizes the cost of making changes
      Is easy to modify and enhance
      Ensures that changes are localized, not system-wide
      Has:
           o High cohesion (focused functionality within modules)
           o Low coupling (minimal dependency between modules)
      Is easier for developers to understand and work with
Key Characteristics of Good Design
     Feature                                      Description
Understandable   Easy to read, analyze, and comprehend for new and existing team members
Modifiable       Supports enhancement and bug-fixing with minimal disruption
Testable         Easy to write test cases for and verify correctness
Reusable         Components can be used in other systems
Robust           Handles errors gracefully
Efficient        Uses resources (memory, CPU) effectively without sacrificing clarity
Conclusion
A good design is not about clever tricks—it’s about clarity, modularity, and long-term
sustainability.
The goal: software that evolves with minimal cost and maximum confidence.
Lesson 17: 2.17. Coupling
What is Coupling?
Coupling refers to the degree of dependency or interconnection between software modules
or components.
  A change in one module may require a change in another if they are tightly coupled.
Understanding Modules
     Design Style                                 Module Definition
Object-Oriented          Typically, a class (group of related attributes & methods) or a
Design                   package
                         Typically, a group of functions performing related tasks, or a
Structured Design
                         source code file
Types of Coupling
    Coupling Type                 Description                            Character
Low Coupling                Few connections              Easier to test, maintain, and reuse
High Coupling               Many connections             Harder to test, maintain, and understand
Measuring Coupling
Coupling is measured by:
      1. Quantity of interfaces between modules
      2. Complexity of each interface (type of communication: data, control, global
         variables, etc.)
Why High Coupling is Bad
         Strong interconnection between components
         High dependency makes modules hard to:
             o Test independently
             o Reuse elsewhere
             o Modify or understand
Why Low Coupling is Good
         Modules are independent
         Easier to test, maintain, and upgrade
         Supports scalability and reusability
How to Reduce Coupling
 1.    Eliminate unnecessary relationships
 2.    Minimize the number of required connections
 3.    Simplify the interfaces (e.g., use data encapsulation)
 4.    Use abstraction layers (e.g., APIs, interfaces)
       Key Takeaway
“A good software design always aims for low coupling and high cohesion.”
Key to Understand the Coupling
The key to understanding coupling is the word module found in the software design usage
description. Unfortunately, the word module has been used to describe a wide range of
physical objects (e.g., the Apollo Lunar Module, modular home, power supply module) and
software constructs (e.g., component, package, class, function).
Module For an object-oriented software design:
      A module is typically a class (i.e., a group of logically related attributes and methods).
       For example, a class that contains methods that validate data entered by a user. For
       very large software systems, a module may be a package of classes.
      A less commonly used interpretation is that a module is a single method found in a
       class definition.
Module For a structured software design:
      A module is typically a group of logically related functions. For example, a set of
       functions that perform validation of data entered by a user could be considered a
       distinct module within a structured design. This type of module is also known as a
       component (or in a very large software system a subcomponent). For example, a
       Python source code file is called a module. Thus, each Python module should contain
       logically related functions.
      A less commonly used interpretation is that a module is a single function found in a
       source code file.
Coupling
The coupling definitions indicate that coupling describes the amount of connectedness
between two or more modules. Thus, a design that has only one module cannot exhibit
coupling. That is, coupling can only be described between distinct modules.
Our intuition suggests having fewer connections between modules mean there is less to test,
maintain, and fix. Having fewer connections between modules is called low coupling, loose
coupling, or weak coupling. A good design is one that exhibits low coupling between its
modules. In contrast, more connections between modules means there is more to test,
maintain, and fix. Having more connections between modules is called high coupling, tight
coupling, or strong coupling. A bad design is one that exhibits high coupling between its
modules
Lesson 18: 2.18. Coupling – Design of a Simple Web App
What is Coupling?
Coupling refers to the degree of interdependence between software modules.
      Low coupling = easy to maintain, modify, and reuse code.
      High coupling = tightly connected modules, changes in one affect others.
Example: Simple Web App
HTML File (index.html)
html
CopyEdit
<!doctype html>
<html>
<head>
           <script type="text/javascript" src="base.js"></script>
           <link rel="stylesheet" href="default.css">
</head>
<body>
           <button onclick="highlight()">Highlight</button>
           <button onclick="normal()">Normal</button>
           <h1 id="title" class="NormalClass">
                   CSS <--> JavaScript Coupling
           </h1>
</body>
</html>
Option A: JavaScript Directly Modifies Styles (High Coupling)
base.js
javascript
CopyEdit
function highlight() {
        document.getElementById("title").style.color = "red";
        document.getElementById("title").style.fontStyle = "italic";
}
function normal() {
        document.getElementById("title").style.color = "inherit";
        document.getElementById("title").style.fontStyle = "normal";
}
         Tightly coupled with CSS styles.
         Any style change must be updated in multiple places (JS & CSS).
         Harder to maintain.
Option B: JavaScript Modifies Class Attribute (Low Coupling)
base.js
javascript
CopyEdit
function highlight() {
        document.getElementById("title").className = "HighlightClass";
}
function normal() {
        document.getElementById("title").className = "NormalClass";
}
default.css
css
CopyEdit
.NormalClass {
        color: inherit;
        font-style: normal;
}
.HighlightClass {
          color: red;
          font-style: italic;
}
       Loosely coupled: JavaScript doesn’t know style details.
       All styling is centralized in CSS.
       Better maintainability and flexibility.
Conclusion
       Option B (changing class) is preferred.
       Promotes low coupling, high cohesion, and clean separation of concerns (logic vs.
        styling).
Lesson 19: 2.19. Cohesion
Cohesion:
       Definition: The degree to which the elements inside a module (such as methods and
        data) belong together.
       Purpose: Measures the strength of the relationship between:
            o The methods and data of a class, and
            o The unifying purpose or concept served by that class.
       High Cohesion:
            o All elements work towards the same goal.
            o Improves maintainability, readability, and modularity.
       A well-designed module or class should aim for high cohesion.
Lesson 20: 2.20. Relationship between Coupling and Cohesion
Cohesion
       Intra-component relationships
       Refers to how closely the tasks within a module are related
       High cohesion means a module focuses on a single, well-defined task, making it
        easier to maintain and understand
Coupling
      Inter-component relationships
      Refers to how dependent modules are on each other
      Low coupling is desirable — modules can function independently, making the
       system more flexible and maintainable
Relationship
      Good design = High Cohesion + Low Coupling
      They support readability, modularity, and maintainability
Difference:
Lesson 21: 2.21. Software Design Strategies Structured and
Object-Oriented Design
Structured Design
      Focuses on functions and the sequence of actions
      System is seen as a set of procedures acting on centralized data
      Action-oriented approach
      Emphasizes:
          o What each function does
          o How functions are organized hierarchically
Object-Oriented Design (OOD)
      Based on information hiding and encapsulation
      System is seen as a collection of objects, each managing its own state
      Objects have:
          o Attributes (state)
          o Operations (behavior/intelligence)
      Objects communicate through message passing
      Decentralized control
Lesson 22: 2.22. Object-Orientation Basic Concepts - The Object
Object
        A tangible or conceptual entity with a defined role in the problem domain
        Represents an individual item with:
            o State
            o Behavior
            o Identity
State
        Represents the current values of an object’s properties
        Encapsulated inside the object
Behavior
        Describes how an object acts/reacts
        Changes based on its state or through message passing
Identity
        A unique property that distinguishes an object from all others
        Answers: “Who provides a specific service?”
Object
Objects are key to understanding object-oriented technology. Look around right
now and you'll find many examples of real-world objects: your dog, your desk,
your television set, your bicycle.
Real-world objects share two characteristics: They all have state and behavior.
Dogs have state (name, color, and breed, hungry) and behavior (barking, fetching,
wagging tail). Bicycles also have state (current gear, current pedal cadence, and
current speed) and behavior (changing gear, changing pedal cadence, applying
brakes). Identifying the state and behavior for real-world objects is a great way to
begin thinking in terms of object-oriented programming.
Take a minute right now to observe the real-world objects that are in your
immediate area. For each object that you see, ask yourself two questions: "What
possible states can this object be in?" and "What possible behavior can this object
perform?". Make sure to write down your observations. As you do, you'll notice
that real-world objects vary in complexity; your desktop lamp may have only two
possible states (on and off) and two possible behaviors (turn on, turn off), but your
desktop radio might have additional states (on, off, current volume, current station)
and behavior (turn on, turn off, increase volume, decrease volume, seek, scan, and
tune). You may also notice that some objects, in turn, will also contain other
objects. These real-world observations all translate into the world of object-
oriented programming.
                                   A Software Object
Lesson 23: 2.23. Object-Orientation Basic Concepts - The Class
Class
       A template for creating similar objects
       Defines properties (data) and behavior (functions/methods)
       Represents an abstraction
Two Views of a Class
   1. Interface (Public View):
          o Declares what the class can do
          o Specifies all operations accessible to other parts of the system
          o “What can I do for you?”
   2. Implementation (Private View):
          o Defines how tasks are done internally
          o Includes data structure and algorithms
          o “How is it actually done?”
The Class
In the real world, you will often find many individual objects all of the same kind.
There may be thousands of other bicycles in existence, all of the same make and
model. Each bicycle was built from the same set of blueprints and therefore
contains the same components. In object-oriented terms, we say that your bicycle
is an instance of the class of objects known as bicycles. A class is the blueprint
from which individual objects are created.
Lesson 24: 2.24. Relationship between Classes and Objects –
Association
Classes & Objects
      Core building blocks of a system
      System behavior is based on how objects interact
Association
      A non-hierarchical relationship between two classes
      One class uses or interacts with another
      Shown with a solid line between class icons
      Can be conceptual (class level) or physical (object level)
      Does not mean all objects are connected, but implies a consistent connection
Attributes of Association
      Descriptive name (what the relationship is)
      Arity (e.g., one-to-one, one-to-many)
      Direction (who uses whom)
      Roles (what role each class plays)
Lesson 25: 2.25. Relationship between Classes and Objects: Aggregation and
Composition
Aggregation
      A whole-part relationship
      The part can exist independently of the whole
      Represented with a hollow diamond
      Considered less significant—often just a modeling placeholder
Composition (Composite Aggregation)
      A stronger form of aggregation
      The part cannot exist without the whole
      Each part belongs to only one whole
      Represented with a filled-in diamond
      Seen as important and meaningful in object modelling
Lesson 26: 2.26. Relationship between Classes and Objects:
Inheritance
Classification and Hierarchy
      Grouping objects into related abstractions
      Helps organize and manage complexity
Inheritance
      A class (subclass) inherits structure and behavior from one or more superclasses
      The subclass can reuse, modify, or extend the features
      Creates a generalization/specialization hierarchy
Inheritance Hierarchy
      Shows relationships between classes
      Triangles represent generalization in diagrams
      Subclasses implicitly possess all features of their superclasses
The "Is-a" Rule
      If class B inherits from class A, then B “is a” type of A
      Example: Dog is a Animal
Lesson 27: 2.27. Object Orientation Basic Concepts Abstract
Classes and Interfaces
Abstract Class
      A class that is partially implemented
      Used when you know the structure but not the full implementation
      Provides basic functionality for other classes to inherit
      Cannot create objects (instances) of an abstract class
Interface
      A mechanism for abstraction
      Contains only abstract methods (no implementation or state)
      Helps define what a class should do, not how
                               !!! Week 03 !!!
Lesson 28: 3.28. Relationships – Basic Concepts Object Oriented
Programming Defined
OOP as defined by Grady Booch:
A method of implementation in which programs are organized as cooperative
collections of objects, each of which represents an instance of some class, and
whose classes are all members of a hierarchy of classes united via inheritance
relationships.
Relationships:
      Hierarchy of classes
            o Inheritance – relationship among classes
      Cooperative collections of objects
            o Association – relationship among instances of classes
Relationships in Object Oriented Concepts
If you are building a house, things like walls, doors, windows, cabinets, and lights
will form part of your vocabulary. None of these things stands alone, however.
Walls connect to other walls. Doors and windows are placed in walls to form
openings for people and for light. Cabinets and lights are physically attached to
walls and ceilings. You group walls, doors, windows, cabinets, and lights together
to form higher-level things, such as rooms. Not only will you find structural
relationships among these things, you'll find other kinds of relationships, as well.
For example, your house certainly has windows, but there are probably many kinds
of windows. You might have large bay windows that don't open, as well as small
kitchen windows that do. Some of your windows might open up and down; others,
like patio windows, will slide left and right. Some windows have a single pane of
glass; others have double. No matter their differences, there is some essential
"window-ness" about each of them: Each is an opening in a wall, and each is
designed to let in light, air, and sometimes, people. In the UML, the ways that
things can connect to one another, either logically or physically, are modeled as
relationships.
In object-oriented modeling, there are two kinds of relationships that are most
important: inheritance and associations.
[Book: Unified Modeling Language (UML) User Guide By Grady Booch James
Rumbaugh Ivar Jacobson]
Lesson 29: 3.29. Relationships – Basic Concepts Association
Association
      A relationship among two or more specified classifiers that describes connections
       among their instances
      Acts as the “glue” that holds a system together
      Without associations, the system is just a set of unconnected classes
Types of Association
   1. Uses Relationship
          o Simple Association
   2. Whole-Part Relationship
        o Aggregation
        o Composition
Lesson 30: 3.30. Relationships – Basic Concepts Aggregation and
Composition
      Association categories:
          o Aggregation
          o Composition
      Both are whole-part relationships
Aggregation
      A form of association that specifies a whole-part relationship
          o Between an aggregate (whole) and a constituent part
The distinction between aggregation and association is often a matter of taste, not semantics
Think of it as a modeling placebo
“Aggregation is strictly meaningless; as a result, I recommend that you ignore it in your own
diagrams.”
— UML Distilled by Martin Fowler
Composition
      A form of aggregation association with:
          o Strong ownership
          o Coincident lifetime of parts with the whole
Lesson 31: 3.31. Object Lifetime and Visibility Inheritance
   B inherits from A
   A is the super or base class and B is the sub or derived class
   A does not know about B
   When an object of Type B is created, a corresponding object of
    Type A is also created
   Conceptually speaking, the object of Type B holds the
    corresponding object of Type A as a private component.
Lifetime of Objects in Inheritance
In above inheritance relationship, B inherits from A. So, A is the
superclass and B is the subclass. While designing the parent-child
relationship, parent class does not know about its child class, so it
means, A does not know about B. This is the first principle while
designing the inheritance.
Secondly, when a child class’s object (B) is created, a
corresponding object of superclass (A) is also created.
Conceptually speaking, the object of Type B holds the
corresponding object of Type A as a private component. Here, private component
means, A’s object is hidden in B’s object. You can say, its component of B. A’s
object is only accessible through class’s B object.
For example, when an object, say b2, of Type B is created, another object, say
a5, of Type A is also created.
     a5 is only accessible from b2.
           exclusive holding
     The life of a5 is dependent upon b2.
           a5 is created with b2 and it dies with b2.
     Cardinality of this relationship is 1:1
Lesson 32: 3.32. Object Lifetime and Visibility Composition
Composition
Definition
       A whole-part relationship
       A form of aggregation association with:
           o Strong ownership
           o Coincident lifetime of parts with the whole
Key Points
      B is the container or whole
      A is the part
      B has many instances of A
      A does not know about B
      A part may belong to only one composite
Additional Notes
      Parts with non-fixed multiplicity may be created after the composite
      Such parts:
           o Share the lifetime of the composite
           o Can be explicitly removed before the composite dies
Composition – object creation and life-time:
      When an object of Type B is created, corresponding instances of Type A are also
       created
      Conceptually speaking, the object of Type B holds the
       corresponding objects of Type A as private components.
           o For example, when an object, say b2, of Type B is created,
               some objects of Type A, say a5 and a6, are also created.
      a5 and a6 are only accessible from b2.
           o exclusive holding
      The life of a5 and a6 is dependent upon b2.
           o a5 and a6 are created with b2 and destroyed with b2.
      Cardinality of this relationship could be 1:1 or 1:m
Multiplicity in Composition
For composition, the multiplicity at the composer’s end is always 1 because,
according to the UML rules, a composed object can’t be shared among composites.
For example:
      A Car has one Engine.
      An Engine is part of one Car.
      A Car has four or five Wheels.
      Each Wheel is part of one Car.
      A Car is always composed of one Body.
      A Body is always part of one Car and it dies with that Car.
      A Car can have any number of Drivers.
      A Driver can drive at least one Car.
      A Car has up to seven Passengers at a time.
      A Passenger is only in one Car at a time.
[Book: Object-Oriented Analysis and Design by Mike O’Docherty]
Lesson 33: 3.33. Object Lifetime and Visibility Association
Object Lifetime and Visibility Association
      One instance of B is associated with many instances of A
      Objects of the two types have independent life times.
      Conceptually speaking, objects of Type B are linked with objects of Type A.
      The relationship is not exclusive. That is, the same instance of A may also
       be linked and accessed directly by other objects.
      Cardinality of this relationship could be 1:1, 1:m, or m:m
Lesson 34: 3.34. Object to Relational Mapping Basics
Object to Relational Mapping Basics
      Relational Database
      Objects
      Mapping between Objects & Relational Database
O2R Mapping (Object to Relational Mapping)
Also Known As
     aka – O2R, ORM, O/RM, and O/R
     Mapping attributes
     Mapping Inheritance
     Mapping Association
     Mapping Composition
Lesson 35: 3.35. Object to Relational Mapping Inheritance
Object to Relational Mapping: Mapping Inheritance
Mapping Inheritance
     Filtered Mapping
     Horizontal Mapping
     Vertical Mapping
Filtered Mapping
     All the classes of an inheritance hierarchy are mapped to one table.
Horizontal Mapping
     Each concrete class is mapped to a separate table and each such table
      includes the attributes and the inherited attributes of the class that it is
      representing.
Lesson 36: 3.36. Mapping Inheritance - Vertical Mapping
Vertical Mapping
In this technique, there exists one database table for each class. Separate tables
provide stable data storage with constrained definitions, but it is more complex to
query a child-class. It requires to write some join statements which reduces the
performance. For example, to get a customer object, it needs to be joined
with User table.
User Table:
UID         Username      Password      Type
U1          Ali           12345         Customer
U2          Aleena        Abcde         Maintainer
Customer Table:
ID                    CustomerNumber        UID
1                     1001                  U1
Maintainer Table:
ID                    EmployeeNumber        UID
2                     1001                  U2
Lesson 37: 3.37. Mapping Composition
Object to Relational Mapping: Mapping Composition
Vertical Mapping
     Each class of the whole-part hierarchy is mapped to a separate table.
     To maintain the whole-part relationship between the whole (composite
      class) and the part (component class), primary key (OID) of the composite
      class is inserted in the part classes as a foreign key.
         o Note the difference between composition and inheritance
Composition – Persistence - Example
     For example, object of type B with oid_b = 21 contains objects of type A
      with oid_a = 1 and oid_a = 2
Lesson 38: 3.38. Mapping Association
Object to Relational Mapping: Mapping Association
     Each class involved in the relationship is mapped to a separate table.
     To maintain the relationship between the classes, primary key (OID) of the
      user class is inserted in the classes that have been used as a foreign key.
     Note that, in the OO world, the client knows the identity of the server
      whereas in the relational world, the table for server holds the identity of the
      client.
     For many-t-many relationship a separate table is used to maintain the
      information about the relationship.
Composition – Persistence - Example
     For example, object of type B with oid_b = 21 uses objects of type A with
      oid_a = 1 and oid_a = 2
Lesson 39: 3.39. Mapping Cardinality of Association
Object to Relational Mapping: Mapping Cardinality of Association
Lesson 40: 3.40. Object to Relational Mapping - Summary
Overview
In this topic, you will study object to rational mapping summary. All relationships,
types of relationships, mapping approaches.
Learning Goals
      Summary
Object to Relational Mapping: Summary
                        !!! Week 04 !!!
Lesson 41: 4.41. Object Oriented Programming –
Inheritance and Polymorphism
Overview
In this topic, you will study polymorphic behavior with example.
Learning Goals
      Polymorphism and inheritance behavior
OOP – Inheritance and Polymorphism
      Inheritance allows one class to inherit members from another.
      Polymorphism allows derived classes to override methods and
       behave differently through base class pointers.
class Polygon {
 protected:
  int width, height;
 public:
  Polygon (int a, int b) : width(a), height(b) {}
  virtual int area (void) =0;
  void printarea()
         { cout << this->area() << '\n'; }
};
class Rectangle: public Polygon {
 public:
     Rectangle(int a,int b) : Polygon(a,b) {}
     int area()
         { return width*height; }
};
class Triangle: public Polygon {
 public:
     Triangle(int a,int b) : Polygon(a,b) {}
     int area()
         { return width*height/2; }
};
int main () {
 Polygon * ppoly1 = new Rectangle (4,5);
 Polygon * ppoly2 = new Triangle (4,5);
 ppoly1->printarea();
 ppoly2->printarea();
 delete ppoly1;
 delete ppoly2;
 return 0;
Questions
          What do we gain by using the base class in the declaration
            Polygon * ppoly1 = new Rectangle (4,5);
            Polygon * ppoly2 = new Triangle (4,5);
          Why not
            Rectangle * ppoly1 = new Rectangle (4,5);
         Triangle    * ppoly2 = new Triangle (4,5);
int main () {
         Polygon * ppoly[10];
         ppoly[0] = new Rectangle (4,5);
         ppoly[1] = new Triangle (4,5);
         // and so on
         for (int i = 0; i < 10; i++)
                         ppoly[i]->printarea();
         // rest of the code
         return 0;
❓ Question 1:
What do we gain by using the base class in the declaration?
cpp
CopyEdit
Polygon * ppoly1 = new Rectangle (4,5);
Polygon * ppoly2 = new Triangle (4,5);
✅ Answer:
By using the base class pointer (Polygon*), we gain polymorphism:
       We can write code that works with any derived shape (Rectangle,
        Triangle, Circle, etc.)
       It lets us store different shapes in a single array or list, like
        this:
cpp
CopyEdit
Polygon* ppoly[10];
ppoly[0] = new Rectangle(4, 5);
ppoly[1] = new Triangle(4, 5);
Then we can loop over all shapes using one single loop:
cpp
CopyEdit
for (int i = 0; i < 10; i++)
  ppoly[i]->printarea(); // Calls the correct shape’s area()
🎯 This is the power of polymorphism — same interface, different
behavior.
❓ Question 2:
Why not write like this instead?
cpp
CopyEdit
Rectangle * ppoly1 = new Rectangle (4,5);
Triangle * ppoly2 = new Triangle (4,5);
⚠️Answer:
You can write it like that, but you lose flexibility:
      Now you need separate code for each type.
      You can’t store both objects in one array or loop over them easily.
      You can’t treat all shapes as a "Polygon" group anymore.
Lesson 42: 4.42. Object Oriented Programming – Object
Creation and Factory Method
Overview
In this topic, you will study object orientation and factory method.
Learning Goals
      Learn object orientation and factory method
🔹 Object Orientation
You're using inheritance and polymorphism — where a base class
(Polygon) can point to derived classes (Rectangle, Triangle) and call their
specific behavior (area()).
🔹 Factory Method
This is a design pattern that helps you create objects without
repeating new Rectangle(...) or new Triangle(...) everywhere.
OOP – Object Creation and Factory Method
int main () {
        Polygon * ppoly[10];
        ppoly[0] = new Rectangle (4,5);
        ppoly[1] = new Triangle (4,5);
        // and so on
        for (int i = 0; i < 10; i++)
                ppoly[i]->printarea();
        // rest of the code
        return 0;
Object creation and Factory Method
Polygon * createPolygon(char t, int w, int h) {
                if (t == ‘R’)
                        return new Rectangle(w, h);
                else if (t == ‘T’)
                        return new Triangle(w, h);
int main () {
        Polygon * ppoly[10];
        for (int i = 0; i < 10; i++) {
                // get type, width, and height of the object
                // to be created
                ppoly[i] = createPolygon(t, w, h);
                // pseudo polymorphic behavior
          }
          for (int i = 0; i < 10; i++)
                  ppoly[i]->printarea();
          // rest of the code
          return 0;
✳️Old way: Hardcoded object creation
cpp
CopyEdit
Polygon * ppoly[10];
ppoly[0] = new Rectangle(4, 5);
ppoly[1] = new Triangle(4, 5);
// ...
        Problem: You need to write new for each type manually.
        If you want to create objects based on user input, this gets harder.
✅ New way: Factory Method
cpp
CopyEdit
Polygon* createPolygon(char t, int w, int h) {
    if (t == 'R') return new Rectangle(w, h);
    else if (t == 'T') return new Triangle(w, h);
    return nullptr;
This function returns the correct object based on the type 'R' or 'T'.
Then in main():
cpp
CopyEdit
for (int i = 0; i < 10; i++) {
    // Get type, width, height from user or data
    ppoly[i] = createPolygon(t, w, h);
You don’t need to repeat new Rectangle(...) or new Triangle(...) — it's
handled inside the factory method.
💡 Why this is better:
Without Factory
                         With Factory Method
Method
Manual object
                         Centralized object creation
creation
Repetitive code          Reusable code
                         Easy to update or add new
Hard to change later
                         types
Poor for user input      Great for dynamic creation
Lesson 43: 4.43. Object Oriented Programming-
The Magic Behind Polymorphism
Overview
In this topic, you will study about the magic behind the polymorphism.
Detail of vtable and vptr that is very important feature to attain the
polymorphic behavior.
Learning Goals
       Learn about the magic behind the polymorphism
OOP – The Magic behind Polymorphism
       Compiler maintains two things:
                vtable: A table of function pointers.
                  It is maintained per class.
         vptr:         A pointer to vtable.
                 It is maintained per object.
      Compiler adds additional code at two places to maintain and
       use vptr.
          o   Code in every constructor. This code sets vptr of the
              object being created. This code sets vptr to point
              to vtable of the class.
          o   Code with polymorphic function call.
      Wherever a polymorphic call is made, compiler inserts code to first
       look for vptr.
      Once vptr is fetched, vtable of derived class can be accessed.
       Using vtable, address of derived class.
Lesson 44: 4.44. Object Oriented Programming-
Implementing Composition
Composition means that a class contains objects of other classes as its
data members.
💡 Think of it like:
An Event has a Time and has a Date.
This "has-a" relationship is what we call
composition.
OOP – Implementing Composition
class Time{
public:
     Time();
     Time(int, int);
     // some setters, getters, and utility functions
     void printTime();
private:
     int hr;
     int min; };
class Date{
public:
     Date();
     Date(int, int, int);
     // some setters, getters, and utility functions
     void printDate();
private:
     int month;
     int day;
     int year;
};
class Event {
public:
Event(int hours = 0, int minutes = 0,
                int m = 1, int d = 1, int y = 1900,
                string name = “Start of 20th Century");
// setters, getters, and other utility functions
     void printEventData();
private:
     string eventName;
     Time eventTime;
     Date eventDay;
};
int main(){
     //instantiate an object and set data for Eid prayer
     Event eidPrayer(6, 30, 12, 8, 2019, “Eid Prayer”);
     eidPrayer.printEventData();
                 //print out the data for object
//instantiate the second object
     Event independenceDay(8, 0, 14, 8, 2019, “National Anthem”);
     independenceDay.printEventData();
                 //print out the data for the second object
     return 0;
Event::Event(int hours, int minutes,
                 int m, int d, int y, string name)
                 : eventTime(hours, minutes),
                 eventDay(m, d, y)
     eventName = name;
void Event::printEventData()
     cout << eventName << " occurs ";
     eventDay.printDate();
     cout << " at ";
     eventTime.printTime();
     cout << endl;     }
Lesson 45: 4.45. Object Oriented Programming-
Inheritance vs Composition
Overview
In this topic, you will learn the inheritance vs composition and advantage
of inheritance over composition.
OOP – Inheritance vs Composition
      The main advantage inheritance has over composition is that it
       allows objects of the derived class to be dynamically bound in the
       same hierarchy as its base classes.
      It is also necessary where virtual methods must be overridden by
       the derived class
         o   A composite aggregate cannot do this.
Lesson 46: 4.46. Implementing Uni-directional
Associations
OOP – Implementing Uni-directional Associations
🔷 What is a Uni-directional Association?
Uni-directional Association means one class knows about the
other, but not vice versa.
💡 Think of it like this:
A course knows which lecturer is teaching it.
But a lecturer does not know which courses they're teaching (in this
setup).
class course
{
private:
          lecturer * L   //        L is a pointer to an
                         //        object of type lecturer
public:
          course();
          void addlecturer(Lecturer *);
          void removelecturer();
};
Lecturer and course are created separately and then linked together.
void course::addlecturer(Lecturer *teacher)
          L = teacher;
void course::removelecturer()
          L = NULL;
Lesson 47: 4.47. Implementing Bi-directional
Associations
🔁 What is a Bi-directional Association?
A bi-directional association means both classes know about each
other.
💡 Example:
        A course knows who the lecturer is.
        The lecturer also knows which course they are teaching.
OOP – Implementing Bi-directional Associations
Example:
        A lecturer can be added to the course and vice versa
In a bi-directional associations both classes must include a reference(via a
pointer) to the linked object.
Problem: User has to update both ends of the relationship.
          Can be achieved by using the operator this.
void course::addlecturer(lecturer *teacher)
    L = teacher;
    L -> addcourse(this);
void lecturer::addcourse(course *subject)
    C = subject;
void main()
       course * SE101 = new course(…);
       lecturer *Fakhar = new lecturer(…);
       SE101->addlecturer(Fakhar);
       // the association is updated for both objects.
N:M associations are implemented using arrays of
pointers from one class to another.
What would happen if it could be added from either side?
void main()
       course * SE101 = new course(…);
       lecturer *Fakhar = new lecturer(…);
       Fakhar->addcourse(SE101);
}
void course::addlecturer(lecturer *teacher)
       L = teacher;
       L -> addcourse(this);
void lecturer::addcourse(course *subject)
       C = subject;
       C -> addlecturer(this);
Control the infinite recursion
void course::addlecturer(lecturer *teacher)
       if (L == NULL) {
               L = teacher;
               L -> addcourse(this);
void lecturer::addcourse(course *subject)
       if (C == NULL) {
               C = subject;
               C -> addlecturer(this);
       }      }
void main()
       course * SE101 = new course(…);
       lecturer *Fakhar = new lecturer(…);
       SE613->addlecturer(Fakhar);
       // or
       // Fakhar->addcourse(SE101);
         …         }
Lesson 48: 4.48. SOLID Design Principles-
Introduction
A good design will manage essential complexities inherent in the problem
without adding to accidental complexities consequential to the solution.
Maintainable Design:
     Cost of system changes is minimal
     Readily adaptable to modify existing functionality and enhance
      functionality
     Design is understandable
     Changes should be local in effect
     Design should be modular
     Goal: low coupling and high cohesion
S.O.L.I.D. Design Principles:
Intended to make software designs more
  •   Understandable
  •   Flexible
  •   Maintainable
SOLID Principle – History:
  •   Originally gathered by Robert C. Martin (aka Uncle Bob)
  •   Arranged by Michael Feathers into an easily remembered, albeit
      ironic, mnemonic: SOLID.
Single Responsibility Principle (SRP), one of the SOLID design principles.
SOLID Design Principles
The SOLID acronym stands for:
      S: Single Responsibility Principle (SRP)
      O: Open/Closed Principle
      L: Liskov Substitution Principle
      I: Interface Segregation Principle
      D: Dependency Inversion Principle
What is SRP?
The Single Responsibility Principle states that a class should have only one reason to
change, meaning it should have only one responsibility. If a class has multiple
responsibilities, it makes the code harder to maintain and modify.
Example of SRP Violating Code
In the first example, the Post class is doing two things:
   1. Creating a post.
   2. Logging errors.
This is a violation of SRP because this class has two responsibilities.
Violating SRP:
class Post
{
    void CreatePost(Database db, string postMessage)
    {
        try
        {
            db.Add(postMessage); // Adds post to database
        }
        catch (Exception ex)
        {
            db.LogError("An error occurred: ", ex.ToString()); // Logs the
error
            File.WriteAllText("\LocalErrors.txt", ex.ToString()); // Writes
error to file
        }
    }
}
Here, the Post class is responsible for both creating the post and handling error logging. This
creates a problem because if we need to change error logging or posting behavior, we have to
change the Post class, violating SRP.
SRP Compliant Code
To follow the Single Responsibility Principle, we should separate the concerns.
We can create a new class, ErrorLogger, that is solely responsible for logging errors. The
Post class will now only be responsible for creating the post, and the error logging will be
handled by the ErrorLogger class.
Applying SRP:
class ErrorLogger
{
    void log(string error)
    {
        db.LogError("An error occurred: ", error);
        File.WriteAllText("\LocalErrors.txt", error);
    }
}
class Post
{
    private ErrorLogger errorLogger = new ErrorLogger();
    void CreatePost(Database db, string postMessage)
    {
        try
        {
            db.Add(postMessage); // Adds post to the database
        }
        catch (Exception ex)
        {
            errorLogger.log(ex.ToString()); // Delegates error handling to
ErrorLogger
        }
    }
}
In this version:
        The Post class is responsible only for creating posts.
        The ErrorLogger class is responsible only for logging errors.
By following SRP, we've made each class focused on a single responsibility, which makes
the code more maintainable and flexible.
Benefits of SRP
        Maintainability: If we need to change how errors are logged, we only need to change
         the ErrorLogger class.
        Flexibility: You can modify or replace the ErrorLogger without affecting the Post
         class.
        Testability: Smaller, focused classes are easier to test individually.
Single Responsibility Principle (SRP) – Example
Multiple Responsibilities
class Post
    void CreatePost(Database db, string postMessage)
        try
            db.Add(postMessage);
        catch (Exception ex)
            db.LogError("An error occured: ", ex.ToString());
            File.WriteAllText("\LocalErrors.txt", ex.ToString());
Class for handling error logging
class ErrorLogger
{
    void log(string error)
        db.LogError("An error occured: ", error);
        File.WriteAllText("\LocalErrors.txt", error);
Single Responsibility!
class Post
    private ErrorLogger errorLogger = new ErrorLogger();
    void CreatePost(Database db, string postMessage)
         try
             db.Add(postMessage);
         catch (Exception ex)
             errorLogger.log(ex.ToString());      }     }}
Lesson 49: 4.49. SOLID Design Principles Single
Responsibility Principle (SRP)
Single Responsibility Principle (SRP)
A class should have only one reason to change.
         Cohesion
               o   Defined as the functional relatedness of the elements of a
                   module
               o   Related to the forces that cause a module, or a class, to
                   change
Responsibility - a reason for change
        What a class does
              o   The more a class does, the more likely it will change
              o   The more a class changes, the more likely we will introduce
                  bugs
SRP – Coupling and Cohesion
        If a class has more than one responsibility
              o   Low cohesion
              o   High coupling - the responsibilities become coupled
             Changes to one responsibility may impair or inhibit the class's
              ability to meet the others
             Leads to fragile designs that break in unexpected ways when
              changed
SRP
        One of the simplest of the principles but one of the most difficult to
         get right.
        Finding and separating conjoined responsibilities is much of what
         software design is really about
        The rest of the principles come back to this issue in one way or
         another
Lesson 50: 4.50. Single Responsibility Principle
(SRP) - Example
Single Responsibility Principle (SRP) – Example
Multiple Responsibilities
class Post
    void CreatePost(Database db, string postMessage)
        try
            db.Add(postMessage);
        }
        catch (Exception ex)
            db.LogError("An error occured: ", ex.ToString());
            File.WriteAllText("\LocalErrors.txt", ex.ToString());
Class for handling error logging
class ErrorLogger
    void log(string error)
     db.LogError("An error occured: ", error);
     File.WriteAllText("\LocalErrors.txt", error); }}
Single Responsibility!
class Post
    private ErrorLogger errorLogger = new ErrorLogger();
    void CreatePost(Database db, string postMessage)
        try
            db.Add(postMessage);
        catch (Exception ex)
            errorLogger.log(ex.ToString());
        }             }        }
Lesson 51: 4.51. SOLID Design Principles Open-
Closed Principle (OCP)
In open close principle, a software artifact should be open for extension
but closed for modification. Modules that conform to the open-closed
principle have two primary attributes, open for extension but close for
modification.
Open-Closed Principle (OCP)
The Open-Closed Principle (OCP):
      Coined by Bertrand Meyer:
      A software artifact should be open for extension but closed for
       modification.
The behaviour of a software artifact ought to be extendible, without
having to modify that artifact.
      Not simply a principle that guides in the design of classes and
       modules.
      Fundamental to good architectural design
If simple extensions to the requirements force massive changes to the
software, then the architects of that software system have engaged in a
spectacular failure.
      Modules that conform to the open-closed principle have two primary
       attributes.
      They are “Open For Extension”.
           o   We can make the module behave in new and different ways as
               the requirements of the application change, or to meet the
               needs of new applications.
      They are “Closed for Modification”.
           o   The source code of such a module is inviolate.
           o   No one is allowed to make source code changes to it.
      Open-Close - Are these two attributes are at odds with each other?
          The normal way to extend the behaviour of a module is to make
           changes to that module.
          A module that cannot be changed is normally thought to have a
           fixed behaviour.
          How can these two opposing attributes be resolved?
Extension through inheritance, composition, and association
                       !!! Week # 05 !!!
Lesson 52:        Open-Closed Principle (OCP) - Example
Lesson 53: liskov substitution principle (LSP)
In liskov substitution principle LSP, functions that use references to base
classes must be able to use objects of derived classes without knowing it.
Liskov Substitution Principle (LSP)
      Subtypes must be substitutable for their base types.
        Deals with design of inheritance hierarchies
Functions that use references to base classes must be able to use objects
of derived classes without knowing it.
Lesson 54:          Liskov’s Substitution Principle (LSP) - Example
class Rectangle
public:
virtual void SetWidth(double w) {itsWidth=w;}
virtual void SetHeight(double h) {itsHeight=w;}
double GetHeight() const {return itsHeight;}
double GetWidth() const {return itsWidth;}
private:
double itsWidth;
double itsHeight;
};
Lesson 55:       Liskov’s Substitution Principle and Inheritance
The True Meanings of IsA Relationship
Validity is not Intrinsic
     A model, viewed in isolation, cannot be meaningfully validated.
     The validity of a model can only be expressed in terms of its clients.
     Square and Rectangle classes viewed in isolation, appeared to be
      self-consistent and valid.
      Viewed from a programmer standpoint who made reasonable
       assumptions about the base class, the model broke down.
      When considering whether a particular design is appropriate or not,
       one must not simply view the solution in isolation.
          o   One must view it in terms of the reasonable assumptions that
              will be made by the users of that design.
What Went Wrong? (W3)
      Isn’t a Square a Rectangle?
      Doesn’t the ISA relationship hold?
      No!
      A square might be a rectangle, but a square object is definitely not a
       Rectangle object.
      Why?
          o   Because the behaviour of a square object is not consistent
              with the behaviour of a Rectangle object.
          o   Behaviourally, a Square is not a Rectangle!
And it is behaviour that software is really all about!
      The LSP makes clear that in OOD the ISA relationship pertains to
       behaviour.
          o   Not intrinsic private behaviour, but extrinsic public behaviour;
          o   Behaviour that clients depend upon.
Lesson 56: Interface Segregation Principle (ISP)
Interface segregation principle:
   •   Clients should not be forced to depend upon interfaces that they do
       not use. If you have an abstract class or an interface, then the
       implementers should not be forced to implement parts that they do
       not care about.
   •   In programming, the interface segregation principle states that no
       client should be forced to depend on methods it does not use.
   •   Put more simply: Do not add additional functionality to an existing
       interface by adding new methods.
   •   Instead, create a new interface and let your class implement
       multiple interfaces if needed.
   •   Deals with non-cohesive interfaces! Coupling
 •   This principal deals with the disadvantages of “fat” interfaces.
     Classes that have “fat” interfaces are classes whose interfaces are
     not cohesive.
 •   The interfaces of the class can be broken up into groups of member
     functions.
     Each group serves a different set of clients.
     Thus, some clients use one group of member functions, and other
     clients use the other groups.
 •   Fat interfaces lead to inadvertent couplings between clients that
     ought otherwise to be isolated.
 •   Fat interfaces can be segregated into abstract base classes that
     break the unwanted coupling between clients.
 •   The ISP acknowledges that there are objects that require non-
     cohesive interfaces
 •   It suggests that clients should not know about them as a single
     class.
 •   Instead, clients should know about abstract base classes that have
     cohesive interfaces.
                      CP1             CP2                CP3
                     OP1              OP2                OP3
                                      OPS
                            --------------------------
                               OP1, OP2, OP3
Lesson 57:
Lesson 58: Dependency Inversion Principle (DIP)
Dependency inversion principle: This principal guide that high-level modules should not depend on
low-level modules. Both should depend on abstractions. Abstractions should not depend upon details.
Details should depend upon abstractions.
      In programming, the dependency inversion principle is a way to decouple software
       modules.
      Natural progression of the Liskov Substitution Principle, the Open Closed Principle
       and even the Single Responsibility Principle.
      The problem of dependency is most often solved by using dependency injection.
      Typically, dependency injection is used simply by ‘injecting’ any dependencies of a
       class through the class’ constructor as an input parameter.
       Using association
Lesson 59:            Code example of dependency inversion principle.
Lesson 60: Good OO design principles
Law of Demeter (LoD)
Law of Demeter and aim:
 It is a Style Rule for building systems. The Demeter Research Group
proposes it in 1987. The Law of Demeter says that if I need to request a
service of an objects sub-part, I should instead make the request of the
object itself and let it propagate this request to all relevant sub-parts, thus
the object is responsible for knowing its internal make-up instead of the
method that uses it.
Law of Demeter – A Style Rule for Building Systems
Origin
        Proposed by The Demeter Research Group in 1987
        Formalized in the paper by Lieberherr & Holland, “Assuring Good Style for Object-
         Oriented Programs”, IEEE Software, Sept. 1989, pp. 38–48
        Widely covered in object-oriented (OO) design literature
Essence of the Law
Also known as the Principle of Least Knowledge, the Law of Demeter (LoD) suggests that:
A method should only communicate with closely related objects and avoid reaching into the
internal structure of other objects.
In simpler terms:
“Talk to friends, not strangers.”
Law of Demeter in Original Form
For any class C, and any method M of C, method M should only invoke methods on the
following:
        The object itself (this)
        Objects passed as arguments to M
        Objects created within M
        Objects held in instance variables of C
        Global variables accessible to M
Why It Matters
        Reduces Coupling: Each module or class is less dependent on the internal structure
         of others.
        Improves Maintainability: Changes in one class are less likely to affect others.
        Encourages Encapsulation: Classes manage their own internal state and behavior.
Trade-Offs
        Pros:
              o   More modular, adaptable, and robust systems
              o   Better encapsulation and cleaner interfaces
         Cons:
              o   May require writing many wrapper methods or delegation methods, which
                  can feel verbose or boilerplate-heavy
Example
Instead of:
java
CopyEdit
Order.getCustomer().getAddress().getZipCode();
Prefer:
Order.getCustomerZipCode();
This encapsulates the internal structure of Customer and Address inside the Order class.
Conclusion
The Law of Demeter encourages good software design by promoting minimal and
meaningful interactions between components. While it may increase code verbosity, the long-
term benefits in maintainability and flexibility outweigh the costs in most systems.
Lesson 61: Law of Demeter (LoD) - Example
Lesson 62: Action-Oriented Design in the
Disguise of object-Oriented Design
Action oriented design, in which you will be described about objects and
classes. Good design practices, design Challenges with OO Paradigm and
god class problem will also be discussed.
Good OOD Practices
      High cohesion and low coupling
      An object must be able to answer:
          o Who I am? → Identity
          o What I know? → Data
          o What I do? → Methods
          o Who I know? → Relationship
      Principle of Delegation
Design Challenges with OO Paradigm
      Poorly distributed system intelligence
      God classes
God Class Problem
      Behavioral Form: can’t answer “What I know?”
      Data Form: can’t answer “What I do?”
      Action-oriented in disguise of object-oriented
      Acts as a central control mechanism
      A super object that does most of the work, delegating only minor tasks to trivial
       classes
Design Solution
      Distribute system intelligence horizontally as uniformly as possible
Lesson 63: Handling Poorly Distributed System
Intelligence
Overview
In this topic, you will study about handling poorly distributed system
intelligence and how to combine intelligence in one place.
Lesson 64:             Modelling Policy – Jacobson’s
Heuristic
Overview
In this topic, you will study about Jacobson’s heuristic in which, you will learn that a policy
information should not place inside the classes involved in decision making.
Student – Course – Course Offering
Scenario
      A Course Offering needs to check if a student has taken the prerequisites.
How to Perform This Function?
      Student: Knows which courses he/she has taken
      Course: Knows its prerequisites
Policy Information
      The decision requires data from two classes:
       → Student and Course
Jacobson’s Heuristic
Policy information should not be placed inside the classes involved in the policy decision.
Why?
      It reduces reusability by tightly coupling the classes to domain-specific logic
      Keeps Student and Course reusable across different policy contexts
                                         !!! Week 6 !!!
Lesson 65: Handling Roles - Player Role Pattern
1. Handling Roles:
"Handling Roles" refers to managing situations where a single object or person takes on
multiple responsibilities or behaviors in different contexts.
Example:
A person can be:
      A Student at a university
      A Teacher in a tutoring center
      A Customer in a bookstore
Each role involves different behavior, data, and interactions.
2. Player Role Pattern:
The Player Role Pattern is a design pattern used in object-oriented design to model a
single object (player) that can take on multiple roles without changing its core identity.
Key Concepts:
      The Player is the core object (e.g., Person).
      Roles are separate classes that define specific behaviors or responsibilities (e.g.,
       StudentRole, TeacherRole).
      The player delegates role-specific behavior to the corresponding role objects.
Benefits:
       Promotes clean separation of concerns
       Makes the system flexible and reusable
       Avoids bloating one class with all behaviors
Example (Simplified in Code Form):
class Person {
    String name;
    // Roles added dynamically
}
class StudentRole {
    void attendClass() { /* ... */ }
}
class TeacherRole {
    void teachClass() { /* ... */ }
}
Handling roles - Player-Role Pattern
Roles
Role Object
Lesson 66: Handling multiple discriminators
using Player-Role Pattern
Handling multiple discriminators using Player-Role Pattern
A discriminator is a label that describes the criteria used in the specialization. It can be
thought of an attribute that will have a different value in each subclass.
Handling multiple discriminators by creating higher-level generalization
      Properties associated with both discriminators have to be present
      All the features associated with the second generalization set would have to be
       duplicated.
      No. of classes can grow very large try adding omnivores and/or
       amphibians!
Handling multiple discriminators by Using Multiple Inheritance
      Avoids duplication of features
      Adds too much complexity - Proliferation of classes not supported by many languages
       like Java and C#
Handling multiple discriminators by Using Player-Role Pattern
      Can very easily add Amphibian
Lesson 67: Software Design and Architecture-
Abstraction-Occurrence Pattern
Abstraction-Occurrence Pattern
Problem
    o   A library has multiple copies of the same book.
    o   How to model?
Solution: Abstraction-Occurrence Pattern
       Abstraction: Represents the general concept — e.g.,                             the
        Book (title, author, ISBN).
       Occurrence: Represents each individual instance —
        e.g., each physical copy of the book (copy ID,
        condition, location).
Structure
       Book → Abstract concept (metadata)
       BookCopy → Occurrence (physical instance tied to one Book)
Benefits
       Clean separation between shared information (Book) and instance-specific data
        (BookCopy)
       Avoids data redundancy
       Easier maintenance and scalability
The Abstraction-Occurrence Pattern
      Context:
          o Often in a domain model you find a set of related objects (occurrences).
          o The members of such a set share common information but also differ from
              each other in important ways.
      Problem:
          o What is the best way to represent such sets of occurrences in a class diagram?
       Forces:
          o You want to represent the members of each set of occurrences without
              duplicating the common information
Abstraction-Occurrence – Examples
Square variant
Lesson 68: Software Design and Architecture-
Reflexive Associations
Reflexive Associations
      An association to connect a class to itself.
      Two main types: Symmetric and Asymmetric.
Asymmetric Reflexive Association
      The ends of the association are semantically different from each other, even though
       the associated class is the same.
      Examples:
           o parent-child, supervisor-subordinate, and predecessor-successor, course-
               prerequisite
// Example - asymmetric association
class Person {
Person *parents[2];
};
// Example - asymmetric association with role name
// on the other end
class Person {
    Person *parents[2];
    vector <Person *> child;
Symmetric Reflexive Association
         There is no logical difference in the semantics of each association end
         Example:
             o mutually exclusive courses
                      students who have taken one course cannot take another in the set
             o If course A is mutually exclusive with B, then course B is mutually exclusive
                 with A
// Example symmetric association.
     class Course {
          Course *mutuallyExclusiveWith[3];
     };
Lesson 69: Software Design and Architecture-
Design Patterns Introduction
Design Patterns – Introduction
         Good OOD is more than just knowing and applying concepts like abstraction,
          inheritance, and polymorphism
         A design guru thinks about how to create flexible designs that are maintainable and
          that can cope with change.
Design Patterns
“Each pattern describes a problem which occurs over and over again in our environment
and then describes the core of the solution to that problem, in such a way that you can use
this solution a million times over, without ever doing it in the same way twice”
      Christopher Alexander, A Pattern Language, 1977
      Context: City Planning and Building architectures
Software Design Patterns
      Search for recurring successful designs – emergent designs from practice
      Described in Gama, Helm, Johnson, Vlissides 1995 (i.e., “gang of 4 book” aka GoF)
      Represent solutions to problems that arise when developing software within a
       particular context.
      Describes recurring design structures
      Describes the context of usage
What Makes it a Pattern?
      A Pattern must:
          o Solve a problem and be useful
          o Have a context and can describe where the solution can be used
          o Recur in relevant situations
          o Provide sufficient understanding to tailor the solution
          o Have a name and be referenced consistently
          o Patterns capture the static and dynamic structure and collaboration among
              key participants in software designs
          o Especially good for describing how and why to resolve non-functional issues
          o Patterns facilitate reuse of successful software architectures and designs.
Lesson 70: Software Design and Architecture-
Elements of Design Pattern
Elements of design patterns
Design patterns have four essential elements:
           o   Pattern name
           o   Problem
           o   Solution
           o   Consequences
Pattern Name
A handle used to describe:
           o  a design problem
           o  its solutions
           o  its consequences
      Increases design vocabulary
      Makes it possible to design at a higher level of abstraction
      Enhances communication
      “The Hardest part of programming is coming up with good variable [function, and
       type] names.”
Factory Method
Problem
Describes when to apply the pattern
  o      Explains the problem and its context
  o      May describe specific design problems and/or object structures
  o      May contain a list of preconditions that must be met before it makes sense to apply the
         pattern
Solution
        Describes the elements that make up the
            o design
            o relationships
            o responsibilities
            o collaborations
        Abstract description of design problems and how the pattern solves it
        Does not describe specific concrete implementation
Consequences
        Results and trade-offs of applying the pattern
        Critical for:
             o evaluating design alternatives
             o understanding costs
             o understanding benefits of applying the pattern
        Includes the impacts of a pattern on a system’s:
             o flexibility
             o extensibility
             o portability
Design Pattern Descriptions
   1.    Name and Classification: Essence of pattern
   2.    Intent: What it does, its rationale, its context
   3.    AKA: Other well-known names
   4.    Motivation: Scenario illustrates a design problem
   5.    Applicability: Situations where pattern can be applied
   6.    Structure: Class and interaction diagrams
   7.    Participants: Objects/classes and their responsibilities
   8.    Collaborations: How participants collaborate
   9.    Consequences: Trade-offs and results
   10.   Implementation: Pitfalls, hints, techniques, etc.
   11.   Sample Code
   12.   Known Uses: Examples of pattern in real systems
   13.   Related Patterns: Closely related patterns
Lesson 71: Categories of Design Patterns
Categories of Patterns
      Creational patterns (5)
          o   Deal with initializing and configuring classes and objects
      Structural patterns (8)
          o   Deal with decoupling interface and implementation of classes and objects
          o   Composition of classes or objects
      Behavioural patterns (11)
          o   Deal with dynamic interactions among societies of classes and objects
          o   How they distribute responsibility
Pattern Types
      Class Patterns (4)
          o   Deal with relationships between classes and their subclasses
          o   Established through inheritance, so they are static-fixed at compile-time
      Object Patterns (20)
          o   Deal with object relationships
          o   Established through association
          o   Can be changed at run-time and are more dynamic
Lesson 72: Benefits and drawbacks of design
patterns
Benefits of Design Patterns
      Design patterns enable large-scale reuse of software architectures and also help
       document systems
      Patterns explicitly capture expert knowledge and design trade-offs and make it more
       widely available
      Pattern names form a common vocabulary
      Patterns help improve developer communication
      Patterns help ease the transition to OO technology
Drawbacks to Design Patterns
      Patterns do not lead to direct code reuse
      Patterns are deceptively simple
      Patterns are validated by experience and discussion rather than by automated testing
      Integrating patterns into a software development process is a human-intensive
       activity.
Design Patterns are NOT:
      Designs that can be encoded in classes and reused as is (i.e., linked lists, hash tables)
      Complex domain-specific designs (for an entire application or subsystem)
They are:
      “Descriptions of communicating objects and classes that are customized to solve a
       general design problem in a particular context.”
Lesson 73: Singleton Design Pattern
The Singleton Pattern (The singleton pattern is a software design pattern that ensures a class
has only one instance and provides a global point of access to it.)
      Context:
            o   It is very common to find classes for which only one instance should
                exist (singleton)
      Problem:
            o   How do you ensure that it is never possible to create more than one instance of
                a singleton class?
      Forces:
            o   The use of a public constructor cannot guarantee that no more than one
                instance will be created.
            o   The singleton instance must also be accessible to all classes that require it
Use the Singleton when:
      There must be exactly one (or fixed number) instance of the class and it must be
       accessible to clients from a well-known access point
Singleton – Structure
Implementation
Lesson 74: Strategy Design Pattern
Overview
It defines a family of algorithms, encapsulates each one, and makes them interchangeable.
Strategy lets the algorithm vary independently from clients that use it.
Strategy Design Pattern
Lesson 75: Design Patterns - Introduction -
Object-Morphing and Strategy ..
Object-Morphing and Strategy Pattern
Avoiding having instances change class
      Object Morphing
          o   When an instance changes its class
          o   An instance should never need to change class
      You have to destroy the old one and create a new one.
          o   What happens to associated objects?
                    You have to make sure that all links that connected to the old object
                     now connect to the new one.
Lesson 76: Facade Design Pattern
                            Facade is a structural design
                                                            pattern that provides a simplified
Problem                                                     interface to a library, a framework,
      There is a legacy application written in C           or any other complex set of classes.
      There is a rich library of functionality that is very difficult to be re-written
      A new GUI-based interface needs to be added to the application
      The application needs to be “object-orientized” to make it communicate/compatible
       with the rest of a newly built system.
How to go about it?
Facade Pattern
      Structural Pattern
      Provides a unified interface to a set of interfaces in a subsystem.
      Defines a higher-level interface that makes the subsystem easier to use.
      Wraps a complicated subsystem with a simpler interface.
      The principal front of a building, that faces on to a street or open space
      A deceptive outward appearance
      Involves a single class which provides simplified methods required by client and
       delegates calls to methods of existing system classes.
      Can be used to add an interface to existing system to hide its complexities.