Object Oriented Design Principles and UML Modeling
Prerequisite Knowledge
This lecture builds on the following concepts from earlier lectures. If any feel unfamiliar, review the linked notes before proceeding.
Previously Covered in This Subject
- 1.3 Analysis versus Design - covered in Lecture 1: Object-Oriented Analysis and Design
- 1.4 Objects, Classes, State, and Behavior - covered in Lecture 1: Object-Oriented Analysis and Design
- 1.5 Abstraction and Encapsulation - covered in Lecture 1: Object-Oriented Analysis and Design
- 1.8 Interfaces - covered in Lecture 1: Object-Oriented Analysis and Design
- 2.3 The OOAD Roadmap: Requirements, Analysis, Design, and Implementation - covered in Lecture 2: Object-Oriented Analysis and Design
- 3.2 The Analysis, Design, and Implementation Pipeline - covered in Lecture 3: Object-Oriented Analysis and Design: Objects, Models, and the Software Process
- 3.6 Class Diagrams and Static versus Dynamic Models - covered in Lecture 3: Object-Oriented Analysis and Design: Objects, Models, and the Software Process
- 7.4 Activity Diagrams - Business Process Flow, Branching and Concurrency - covered in Lecture 7: System Sequence Diagrams, Activity Diagrams and UML Foundations
- 8.2 The Domain Model and the Conceptual Class Diagram - covered in Lecture 8: Object-Oriented Analysis and the Domain Model
- 9.4 Representing Design - UML Interaction, Class and State Diagrams - covered in Lecture 9: Object Oriented Design with UML Interaction Models
- 10.1 From Analysis to Design and Responsibility-Driven Design - covered in Lecture 10: Designing Object Systems with GRASP and Interaction Diagrams
- 11.8 Design Axioms, Theorems, Information Hiding and the Open-Close Principle - covered in Lecture 11: GRASP Patterns and Design Principles - Polymorphism, Indirection, Fabrication and Protected Variations
# Object Oriented Design Principles and UML Modeling
12.1 From Analysis to Design — Modules, Components, and Packages
12.1.1 The Transition from Problem Understanding to Solution Building
Analysis is already done. The problem domain has been understood and decomposed into objects. Real-world organizations, entities, and people performing roles and responsibilities have been identified. Design now converts those problem-domain objects into good software objects and logical solutions. The work is no longer about what the system is, but how to build it as software.
A viewpoint repeated throughout is that learning to design is learning from existing good solutions. No single way teaches design. Design is a creative process refined through past experience, the way one thinks, and studying multiple authors. Patterns are one such window — collections of problem and solution that document what has worked before, so a new system does not start from scratch. Another window is the Class-Responsibility-Collaborator (CRC) card approach, which helps learn about objects in design by writing down a class, its responsibilities, and its collaborators.
12.1.2 Logical Organization into Modules and Packages
A system is built as different modules, also called components. Think of a module as a logical grouping with its own responsibilities. Within a module there may be sub-modules and subclasses. In object-oriented systems the component is the logical entity, and within components there are classes. As a physical implementation detail, a component maps to a package in languages such as Java — a namespace that groups related classes — while logically it remains the same module or component concept. Packages aggregate classes that belong together.
12.1.3 Student Questions and Answers
Q: How do you design anything? What should a design have? A: Start where analysis stopped. Take the objects found in analysis and decide how they become software objects with clear responsibilities and collaborations. Define modules or components around responsibilities, put related classes into the same package, and apply constraints on those modules so each does what it is supposed to do. Learn by studying existing designs, patterns, and CRC cards, and keep refining the decomposition you already have.
12.1.4 Industry Applications
Real-world: In large products the same logical component grouping is used to structure teams and releases — for example a billing component, an inventory component, or a user-management component — each owned by a team and shipped as a package or library.
Hook — Why does the shift from analysis to design feel hard? Think of analysis as making a map of a city as it is — streets, buildings, people. Design is deciding how to build a new quarter using that map, choosing materials, walls, and wiring. The map tells you what exists; the blueprint tells you how to build so it stands and can be extended later.
Intuition — From what to how. Analysis answers "what does the world do?" Design answers "how will software do it well?" A real-world Customer who places orders becomes a software Customer class that holds a customerId, knows its orders, and collaborates with Order and Payment. The name stays, the responsibility sharpens. Where the analogy breaks: real people change roles freely; software objects must have crisp boundaries or they become hard to test.
Formalizing the transition. Let be the set of analysis objects (domain concepts with responsibilities observed in the problem). Let be the set of design objects (software classes with operations, attributes, visibility). Design is a mapping that may split, merge, or invent objects, such that every use case can be realized by collaborating objects while preserving the vocabulary of for low representational gap. A good keeps traceability: you can still point from a software Sale back to the domain Sale.
Visual intuition: imagine two columns. Left column lists analysis sticky notes: Customer, Order, Product, Clerk. Right column shows design packages: domain.sales, domain.inventory, ui. Arrows connect each sticky note to one or more boxes on the right; some arrows split (one analysis concept becomes two design classes), some boxes have no left arrow (invented controllers or mappers). The takeaway: design reuses the analysis vocabulary but is not a photocopy.
Module, component, package — three views of the same grouping. A module is the logical grouping of responsibilities (e.g., "billing"). A component is the UML logical grouping that may expose interfaces. A package (Java com.shop.billing, C# namespace) is the physical namespace that holds the classes. In design you reason about modules; in code you create packages; in UML you may draw either as packages or components. The hierarchy is flexible: a module may contain sub-modules, which contain classes.
Example — Grouping a tiny shop. Suppose you have classes Customer, Order, OrderItem, Product, Payment, CashDrawer. A poor design puts all six in one package shop. A better grouping is: domain.sales holds Order, OrderItem; domain.catalog holds Product; domain.customer holds Customer; techservices.persistence holds mappers. Now a change to Product pricing touches only domain.catalog and its dependents, not the UI. The payoff appears in build times and team ownership.
Scope — Package does not equal deployment. A package is a namespace, not a process or server. Two packages may deploy to one JAR or to two microservices; that choice is a deployment decision. Do not draw a database as the bottom layer of a package diagram — it is an external resource, not a logical layer.
Pitfall — Analysis paralysis vs design invention. Beginners either copy every analysis class one-to-one into code (leaving clumsiness) or invent a new class for every method (exploding count). Ask for each class: does it have one clear purpose you can state in one sentence? If not, split or merge before you code.
Recap + Bridge. Analysis gives you the domain objects and their responsibilities; design reshapes them into software modules and packages with clear collaborations. That reshaping is guided by principles (simplicity, axioms) and by documented experience (patterns, CRC). Next we ask what makes any reshaping good — the answer starts with simplicity.
Real-world and domain connection: product companies keep a stable domain layer precisely because this mapping is strong. A retail POS, an e-commerce site, and a mobile app can share the same Sale, ProductDescription, and Payment classes while swapping the ui layer. That reuse is the payoff for doing the transition carefully.
12.2 Fundamental Design Goals — Simplicity and Occam's Razor
12.2.1 Minimal Complexity as the First Rule
The most basic rule is to keep complexity minimal. Complexity reduction is a central aim of any design. If a solution is simple, people will actually use it. Simplicity with the least complexity is stated as a fundamental goal.
The guiding idea invoked is Occam's Razor, attributed to the 14th-century scholar William of Occam: prefer the simpler explanation or simpler model over the complex one when both achieve the aim. The same principle is used in machine learning where a simpler model is preferred to a complex one, and in software design where a less complex arrangement is preferred.
12.2.2 How Simplicity Is Pursued
Simplicity is pursued by reuse of what already exists, by keeping dependence between parts low, and by keeping each component small and focused on a single ownership. Three practical handles are named: make things simple by breaking them into smaller pieces, reuse existing designs and built-in classes, and make modules loosely coupled — each independent and doing only what it is supposed to do. Least dependence and single ownership reduce the number of paths, states, and interactions a reader or tester must hold in mind.
With those handles the design also becomes highly maintainable. Software maintenance is called a big challenge, so a design that is simple today must also remain affordable to change later. Keeping coupling low and cohesion high directly serves that maintainability.
12.2.3 The Trade-Off Around Class Count and Integration
Minimizing complexity creates a tension. Simpler individual pieces usually means more classes. More classes means more integration and more integration testing. The spoken source states this trade directly: increasing the number of classes helps keep each piece simple but makes integration a challenge. No design decision has all advantages. Every pattern or choice brings some advantages and some disadvantages. The aim is a design that is better than the existing thing, gives enhanced performance, and is easier to manage because its complexity is lower, so it can execute and evolve more cleanly.
12.2.4 Industry Applications
Real-world: Teams favour a library of small reusable classes over a few large monoliths because small single-purpose classes are easier to understand, test, and reuse across products, even though the system then contains more integration points.
12.2.5 Exam Notes
Exam note: The question on why simplicity matters and how Occam's Razor guides design choices is a natural conceptual question. Be ready to relate coupling, reuse, and simplicity to complexity reduction.
Hook — Why prefer simple? Because software spends most of its life being read and changed, not written. A design with 20 states and 100 interaction paths needs 20 times 100 tests in spirit; a design with 5 states and 10 paths needs far fewer. Simpler is cheaper to test, safer to change, and more likely to be used correctly.
Occam's Razor as a design rule. Given two designs that satisfy the same functional requirement, choose the one that introduces fewer new concepts, fewer dependencies, and fewer special cases. An explanation in science that fits data with three laws beats one that needs ten; a model in machine learning with 5 parameters that predicts well beats one with 50 that predicts slightly better but overfits; a software module with one clear responsibility beats one that handles three unrelated concerns. Occam Razor simpler model preferred in machine learning and software design complexity reduction is the classic invoking example.
Three handles, one aim. 1) Decompose: break a large responsibility into smaller single-purpose classes. 2) Reuse: apply a known pattern or library class instead of inventing a new mechanism. 3) Reduce dependence: make messages infrequent and data carried small. Each handle lowers the information a developer must hold while reading code, which is the working definition of simpler.
Think of a kitchen. A single multi-tool that chops, blends, and bakes is complex — one failure stops everything, and users must learn every mode. A set of small tools — knife, blender, oven — each does one job well; you combine them in simple ways. Where the analogy breaks: software tools also talk to each other, so their interfaces must stay narrow or the combination itself becomes complex.
Worked example — Reuse vs invention. Need to notify many UI views when a domain object changes. Option A: each domain class calls each view directly (custom wiring, many dependencies). Option B: reuse the Observer pattern via Java PropertyChangeListener: domain object fires propertyChange, views register. Option B introduces zero new control coupling — views depend on a stable interface, not on concrete domain classes — and removes duplicated wiring. That is the razor in action: reuse a standard solution to shave custom code.
Assumption — Simpler does not mean trivial. Simplicity is relative to the problem. A tax engine is not simple, but its design can be simpler than alternatives with tangled dependencies. The razor does not justify leaving out a needed responsibility; it justifies achieving each responsibility with the least mechanism that is clear and correct.
Visual: plot complexity on the vertical axis, number of classes on the horizontal. As you split a monolith into focused classes, per-class complexity drops sharply, total system complexity drops then flattens, while integration points rise slowly. The sweet spot is where per-class complexity stays low and integration stays understandable.
Pitfall — False simplicity. Hiding complexity in a giant utility class called Manager or Util looks simple (fewer files) but is not — it just moves complexity into one place where cohesion collapses. Another trap is chasing reuse so hard that you depend on a heavy framework for a tiny need. Simple means focused and honest about dependencies, not few files at any cost.
Intuition — Why more can be simpler. A class with 800 lines that handles orders, discounts, taxes, and invoicing is simpler to count (one class) but harder to understand. Five classes with 150 lines each — Order, Pricing, Tax, Discount, Invoice — are more pieces to integrate, but each can be tested alone, named well, and changed independently. The integration cost is real (you must wire them), but it is paid once; the comprehension cost of the monolith is paid every time someone reads it.
Recap + Bridge. Occam's Razor tells us to shave away unnecessary concepts. In software that means decomposing, reusing, and decoupling. The immediate consequence is a trade-off: simpler pieces mean more pieces, so integration rises. Managing that trade is the job of the axioms that follow.
12.3 Reasoning About Design — Axioms, Theorems, and Corollaries
12.3.1 Why Formal Reasoning Is Needed
Any set of classes could compile, but an engineer must answer why this set was chosen: why this class exists, what its purpose is, why a particular method belongs to this class and not to another, and what reason supports the decision. As an engineer, the answer cannot be only yes or no. It must carry a reason.
Because software design, like other engineering disciplines, tries to support decisions with calculation, the lecture introduces a small formal vocabulary borrowed from engineering and mathematics: axiom, theorem, and corollary, and the related idea of formal methods such as Z notation and formal verification, which are used to make designs more calculable and testable.
12.3.2 Definitions of Axiom, Theorem, and Corollary
An axiom is a fundamental truth for which no mathematical proof is offered. It is hypothesized by observing a large number of cases and noting a common phenomenon. It remains valid until a counter example or exception invalidates it. In that sense it is always valid in practice.
A theorem or proposition comes from axioms. If the axioms are valid, the theorems that follow are also treated as valid, similar to a law or principle. A corollary is also a proposition that follows from axioms or from other propositions or theorems. The lecture stresses that these three levels form a reasoning chain through which design decisions are justified.
The source language in the raw speech renders "axiom" as "exam" owing to speech-to-text noise. The meaning throughout is axiom, theorem, and corollary.
12.3.3 Reference to Source Material
The design rules that follow are said to be taken from the book by Ali Bahrami, described as an older text the speaker studied, and from a second text rendered as "Laubic" in the spoken source, which is an uncertain author name. The point made is that design cannot be learned from a single author because it is a creative process; learning from multiple authors and making a practical synthesis for the particular system is required.
12.3.4 Student Questions and Answers
Q: We have many rules, theorems, axioms, and corollaries. How do they help us say why we took a design decision? A: Use the chain: start from an axiom that is accepted because it holds across many observations. Derive theorems and corollaries from it. Then point to the corollary or theorem that supports why a particular class was created or why a method was placed where it was, so the decision has a stated principle behind it.
12.3.5 Industry Applications
Real-world: Teams in review meetings are expected to justify a decomposition by citing cohesion and coupling principles rather than intuition alone, which is the workplace equivalent of citing a corollary.
Hook — "It works" is not enough. A program that compiles and passes one test may still be badly designed. Engineering asks not just "does it run?" but "can we argue why this structure, and can we test whether the argument holds when requirements change?" That argument needs a vocabulary.
Why borrow math language? In math, an axiom is accepted without proof; a theorem is proven from axioms; a corollary follows quickly from a theorem. In design, axioms play the same role: they are widely observed truths (e.g., "low coupling helps change"). Theorems and corollaries translate them into actionable rules ("make data coupling preferred", "keep each class single-purpose"). Formal methods like Z notation push this further by writing specifications in logic so that proofs or model checks can be run.
The chain, in simple terms. Axiom — a base belief you accept because it has held across many projects and has no strong counter-example (e.g., "maintain independence between parts"). Theorem — a principle you derive if you accept the axiom (e.g., "coupling should stay low"). Corollary — a more specific rule that follows from the theorem (e.g., "data coupling is preferable to stamp coupling" or "a class should have a single purpose"). The chain lets you point from a code placement choice up to a base axiom in one or two steps.
Example of the full chain: Axiom — Independence matters → Theorem — Low coupling is desirable → Corollary — Pass simple data, not whole structures that expose internals, when a single field is needed. Each step narrows the guidance while keeping the justification.
Assumption — Axioms are empirical, not proven. In software, axioms are not mathematical certainties; they are strong empirical generalizations. They hold "until a counter-example invalidates them." That is why design texts use words like metrics and measurement — we keep testing whether the axioms still predict maintainability, and so far they do.
Source synthesis. The design rules that follow are taken from the book by Ali Bahrami, described as an older text the speaker studied, and from a second classic text by authors such as Rumbaugh or Booch. Design cannot be learned from a single author because it is a creative process; learning from multiple authors and making a practical synthesis for the particular system is required. No single book "owns" design; comparing authors and re-deriving for your system is the intended practice.
Pitfall — Single-source mimicry. Copying one author's package layout verbatim into a different problem guarantees mismatch. Use the axiom chain to adapt: keep the axioms, re-derive the corollaries for your context, and only then choose classes.
Recap. Axioms give you the base truth, theorems derive principles, corollaries give you the specific design rules you can cite. Z notation shows the formal extreme; even without formal proof, the vocabulary lets you justify "why this class, why this method here" with more than intuition.
12.4 The Two Design Axioms — Independence and Information
12.4.1 Independence Axiom — Low Coupling
Two axioms are presented as the foundation of object-oriented design: the Independence Axiom and the Information Axiom. The independence axiom is about keeping dependence low, which is the same concept as coupling. It states that parts of a design should be as independent as possible. This is applied directly to object-oriented classes and objects.
The lecture asks repeatedly how coupling should be understood between two classes: what coupling means in an object-oriented system, how it happens, and how strongly two objects are coupled. The answer developed is that coupling is the amount of information being exchanged between collaborators — how much information one object needs from another to create that object or to execute a method. That is the working measure of coupling in this lecture.
12.4.2 Information Axiom — High Cohesion
The information axiom is about how much information is being passed on or held, which maps to cohesion and information hiding. It is concerned with the private variables and the amount of information a class exposes or that flows between objects. Where the independence axiom looks outward at connections between objects, the information axiom looks inward at how focused and self-contained a single object is. Both are described as yin and yang of software design — concepts that existed before object orientation but appear within object orientation as private variables, visibility, and information distribution.
12.4.3 Measurement and Related Trends
Both axioms connect to measurement through metrics (rendered as "matrices" in the spoken source). The speaker notes that the design's goodness will be talked about through metrics such as Depth of Inheritance Tree (DIT) and Lack of Cohesion of Methods (LCOM), with the full metrics discussion deferred to a final session. The existence of these metrics is the point here: coupling and cohesion are not only slogans but have defined measures.
12.4.4 Mathematical Link Between the Axioms
The relationship stated to link the two ideas is that highly cohesive objects carry less extraneous information and therefore need fewer outward connections, which reduces coupling. In condensed form the intent is captured by: highly cohesive less information content lower coupling. This is the logical bridge that the corollaries later exploit.
12.4.5 Student Questions and Answers
Q: With respect to object orientation, what kind of coupling are we talking about? How do you define it and how do you measure it for classes? A: Coupling is dependence. Between two classes it is how much information is exchanged for object creation and method execution — how many attributes and methods one collaborator needs from another. The more methods or attributes a class depends on, and the richer the structure it receives, the higher the coupling. The measure therefore involves counting depended-on methods and attributes and looking at the complexity of the data passed.
Q: What is meant by information in the information axiom? Is it only private variables? A: It includes private variables and all internal information a class holds or transmits. The axiom asks how much information is being passed on, whether through parameters, shared structures, or exposed state. Cohesion is the inward-facing form of the same concern: whether a class and its methods serve one coherent purpose with minimal extraneous information.
12.4.6 Exam Notes
Exam note: Expect to state the two axioms by name, map independence to coupling and information to cohesion, and explain that they are the most fundamental rules from which the six corollaries follow.
Hook — What makes a design feel good? Two forces: independence (parts that can change alone) and information focus (each part holds only what it needs). The lecture calls them yin and yang — outward and inward views of the same health. Independence axiom and information axiom are the two axioms foundation.
Independence axiom, stated. Design parts should be as independent as possible. In object terms: a class should need as little knowledge of another class's internals as possible to use it. Coupling is that knowledge — counted as number of methods called, number of attributes read, and richness of data passed. Lower is better because change in the supplier then affects fewer clients. Repeated questioning what coupling means leads to re-explanation amount information exchanged collaborators is the teaching trace here.
Information axiom, stated. A design should minimize the amount of information that must be exposed or carried to get work done, and each object should hold only information that belongs to one coherent purpose. High cohesion is the inward sign that the axiom is satisfied: methods and attributes of a class belong together and serve one purpose. Yin and yang metaphor for independence coupling and information cohesion as dual forces captures the duality: you cannot achieve one fully without the other.
From slogans to numbers — metrics. Both axioms connect to measurement through metrics. The design's goodness will be talked about through metrics such as Depth of Inheritance Tree (DIT) and Lack of Cohesion of Methods (LCOM), with the full metrics discussion deferred to a final session. DIT counts the longest path from a class to the root of its hierarchy — a rough proxy for inheritance reuse and complexity. LCOM counts how many method pairs share no attributes, higher meaning lower cohesion. Both are defined in the classic Chidamber and Kemerer suite and are still reported by modern quality tools.
Visual: two overlaid charts. Left: coupling as fan-out arrows between classes; fewer arrows means lower coupling. Right: cohesion as clustering of methods and fields inside one class; tight cluster means high cohesion. The takeaway: fewer outward arrows and tighter inward clusters travel together.
The bridge as a formula. The intended link can be written as a chain:
Read it as: if a class is highly cohesive, it holds only focused information; with less extraneous information carried, it needs fewer dependencies; with fewer dependencies, coupling falls. Highly cohesive less information content lower coupling link with arrow notation is the formula recorded in the manifest. The arrow is logical implication, not arithmetic.
A tiny illustration: a Report that formats, queries, and emails has low cohesion and must couple to DB, template, and mailer. Split into Query, Renderer, Mailer: each is cohesive, each couples only to what it truly needs, and total coupling per class falls even though the system has more classes.
Pitfall — Counting only calls. Beginners count only method calls and ignore data richness. Passing a whole Customer record when only customerId is needed is higher coupling than a single scalar, even with the same call count. Always count both calls and data shape.
Recap + Bridge. Independence (low coupling) looks outward at dependence between objects; information (high cohesion) looks inward at focus within an object. Metrics DIT and LCOM will later let you measure both. Their bridge — highly cohesive implies less information implies lower coupling — is the logic the six corollaries will exploit.
12.5 Coupling in Depth — Types, Measures, and Desirable Levels
12.5.1 What Determines Coupling Strength
Coupling is decided by the number of methods and number of attributes one object depends on in another, and by the shape of the data being passed. Interaction coupling is message passing between components. It is desirable to keep messages as simple and as infrequent as possible — what is called the complexity wavelength in the spoken source. Even when some interaction is necessary, heavy dependence should not be there.
Two broad families are named for object orientation: interaction coupling and inheritance coupling. Inheritance coupling is dependence through a superclass to subclass that is well understood. Interaction coupling is dependence through messages and shared data.
12.5.2 Traditional Coupling Spectrum from Highest to Lowest
The lecture enumerates the classic spectrum, stated from higher to lower coupling:
- Content coupling is the highest. It occurs when there is a direct connection by referring directly to attributes and methods of other objects, accessing their internals. Directly accessing methods and variables of another object is the content-coupling case.
- Common coupling involves shared global data that two objects both use. It is noted as largely absent in object orientation and only very rarely done.
- Control coupling occurs when one object explicitly controls the processing of another by passing control information that steers which path that other object takes.
- Stamp coupling occurs when an aggregated data structure is passed to another object that uses only a part of it. The receiver gets the whole structure but needs only one component or field.
- Data coupling is the lowest and most acceptable form. Simple data items are passed whose elements are actually used by the receiving object. Because some data must be worked upon, data coupling is considered fine.
The summary given is that content coupling is on the higher side and data coupling is fine. Stamp coupling sits above data coupling because extra unused structure travels between objects. In general, the coupling felt by an object grows with the number of depended-on methods, the number of depended-on attributes, and the richness of the passed structure.
12.5.3 Interaction Coupling and Inheritance Coupling — How Much Is Desirable
Interaction coupling is described as desirable to keep little — minimize the number of messages sent and do not send them in a very frequent manner. Keep messages simple and infrequent. Inheritance as coupling is different: the speaker states explicitly that inheritance coupling is wanted more, that higher inheritance is desirable, and that there is much scope to refactor designs to use more inheritance. The caveat added is that excessive reuse should still be avoided and that each specialization class should not accumulate many unrelated methods. So the advice is to use more generalization and specialization through inheritance, but keep each subclass focused.
12.5.4 Tight Coupling Illustrated
An illustration is offered: one object being dependent on all the different objects in the system is a very tight coupling. Dependence on a few objects is tolerable, but dependence on all objects becomes crucial and must be reduced. The takeaway is to build examples from real-world situations for coupling and cohesion and for the information axiom, and to be able to show a tightly coupled arrangement and then reduce it.
12.5.5 Student Questions and Answers
Q: How can we tell how much coupling we have and how to reduce it? A: Look at what information is exchanged when you create an object or execute a method, and count the methods or attributes of collaborators that you touch. Replace direct reference to internal attributes and methods, replace global sharing, and replace passing a whole structure when only one field is needed with passing simple data items. Also reduce how often messages are exchanged and make each message simpler.
Q: If inheritance is also coupling, should we avoid it? A: Inheritance is coupling through the superclass to subclass chain, but it is the kind of coupling that is wanted here. The speaker encourages using more inheritance to capture generalization and specialization and to move common behaviour to super classes, while keeping each subclass single-purpose and not loading it with unrelated methods.
12.5.6 Industry Applications
Real-world: In industry a service that directly reaches into another service's internal fields is treated as content-like coupling and is refactored to a data-coupled interface that passes only the needed value objects.
12.5.7 Exam Notes
Exam note: Be prepared to list the coupling types in order from highest to lowest, give a short definition of each, and state that data coupling is the preferred low end and that inheritance coupling is deliberately pursued in this lecture's design view.
Counting coupling. For a pair of classes , tally: (1) methods of that calls, (2) attributes of that reads, and (3) richness of data passed (plain values vs whole aggregates). Interaction coupling is the count over calls and data; inheritance coupling is the count over inherited members and override obligations. A message price = catalog.getPrice(itemId) with one input and one scalar output is the lightest possible interaction coupling. Interaction coupling and inheritance coupling are the two families for object orientation.
The spectrum as a table — content, common, control, stamp, data from highest to lowest. Ranked highest (worst) to lowest (best):
| Level | What happens | Why it hurts |
|---|---|---|
| Content | reads/writes 's internal fields or reaches into 's methods directly | Change to 's internals breaks |
| Common | and share a global variable or singleton map | Hidden dependency, hard to test |
| Control | passes a flag that tells which branch to take | knows 's control flow |
| Stamp | passes a whole record/structure, uses one field | Extra structure leaks, version pressure |
| Data | passes simple values that fully uses | Minimal knowledge, easy to replace |
Prefer data coupling; refactor stamps toward data when the extra fields are never used. Content coupling is the highest, data coupling is fine is the lecture's summary.
Example — From stamp to data. A naive printInvoice(Order order) passes the whole Order with 15 fields but the printer uses only order.total and order.address. That is stamp coupling: a change to Order's internal list layout forces the printer to recompile even though printing did not need that list. Refactor to printInvoice(Money total, Address address) — now only two simple values cross the boundary. The call site does slightly more work, but the printer's coupling collapses to data coupling and becomes immune to unrelated Order changes.
Scope — Two couplings, two attitudes. Interaction coupling — messages between unrelated objects — keep low: few calls, small data, no exposure of internals. Inheritance coupling — dependence of subclass on superclass — is wanted more in this lecture's framing, because it expresses genuine generalization to specialization and lets common behaviour be written once in the parent. Higher inheritance is desirable here, with the caveat that each specialization class should not accumulate many unrelated methods. excessive reuse should still be avoided.
Worked example — Tight coupling and its reduction. Tightly coupled object dependent on all objects versus dependence on few objects is the core illustration. Imagine a GodReport class that directly calls Customer, Order, Product, Inventory, Payment, and Shipping — six dependencies — and passes whole aggregates between them. Every change in any of those six forces GodReport to be inspected. That is tight coupling: one object dependent on all objects is very tight coupling and must be reduced. Refactor by introducing ReportData value objects and a ReportService that asks each domain object for only the needed scalar (e.g., order.getTotal(), inventory.getStockCount(productId) — data coupling). Now the coordinator depends on narrow interfaces, each domain object remains cohesive, and the dependency fan falls from six rich dependencies to two narrow ones. One object being dependent on all the different objects in the system is a very tight coupling warning — reduce it.
Visual: draw a star with GodReport in the center connected to six nodes with thick arrows labeled with whole structures. Redraw as a chain where a coordinator calls each domain object with one scalar and assembles a small transfer object — arrows become thin and labeled with single values. That is the exam-ready diagram for "show tightly coupled then reduce it."
Pitfall — Shallow promise of reuse. Creating a hierarchy to share two fields while adding three unrelated methods to each child violates single-purpose. That reuse costs more than it saves. Genuine generalization shares both data and behaviour that change together; opportunistic sharing that groups whatever happens to look similar today often creates brittle coupling.
Recap. Coupling grows with number of depended methods, attributes, and data richness. Data coupling (simple values fully used) is the preferred low end; content is the high end. Interaction coupling minimize, inheritance coupling pursue genuinely, but keep each subclass single-purpose.
12.6 Cohesion, Information Hiding, and Visibility
12.6.1 Cohesion and the Information Axiom Revisited
Cohesion applies to a particular class: whether its methods and carried data belong together for a single coherent purpose. A method that carries multiple functions should not be done, and a class that loses focus should be challenged on its role in the system. High cohesiveness means each object carries less extraneous information, which in turn reduces the need to talk to others. The lecture phrases this as maximum object cohesiveness being required and as the reason that large numbers of simpler classes are acceptable.
A direct consequence stated is that high cohesion and low coupling move together. If clumsy classes with unrelated data appear, the response is to break them into new classes.
12.6.2 Information Hiding Through Visibility
Information hiding is described as a difficult part of the same idea. It is implemented through visibility keywords, discussed for Java as public, private, protected, and package. The most stringent among all these is private: if a method is made private, no other class can access it. The distinction between protected and package is raised as important, and the speaker notes that hiding through these levels gets very little attention even though it matters.
The difference that is explained is that protected and package control access across packages and across the inheritance hierarchy in different ways. Protected access is visible to subclasses even across packages but within the hierarchy, while package access, also called default, is visible only within the particular package and not across packages, even to subclasses. The speaker checks for understanding by asking which is more stringent and whether they are the same, noting that many listeners were not following that distinction. The summary rule is that private restricts most, then package and protected differ in the cross-package versus hierarchy dimension, and all of these choices are part of information hiding.
12.6.3 Student Questions and Answers
Q: What is the difference between protected and package? When should we use which? Which is more stringent? A: Private is the most stringent of all. Protected allows access to subclasses even across packages because it is tied to the inheritance hierarchy, while package, the default with no keyword, allows access only within the same package. So for cross-package subclass access you would need protected, for within-package-only sharing you keep package access. The precise choice depends on whether you intend hierarchy-based sharing or package-local sharing.
12.6.4 Industry Applications
Real-world: Teams treat visibility as an encapsulation contract: internals stay private, package-level helpers remain package-private, and only the intended extension points are marked protected, which keeps the public surface small.
Cohesion as focus. A highly cohesive class answers "what single job do you do?" in one sentence. All its methods help that job; all its attributes are needed for that job. Low cohesion (or lack of cohesion) means the class answers with "and" — "I handle orders and taxes and emailing and logging." The remedy is not to comment better but to split: create two or three classes each with one job. High cohesiveness means each object carries less extraneous information, which in turn reduces the need to talk to others. Maximum object cohesiveness being required is the lecture phrase.
Analogy: a good restaurant kitchen has stations — grill, pastry, sauces — each station holds only tools for its dish. A "do-everything" station that stores fish, bread, and invoices has low cohesion and must be visited by everyone, creating coupling.
Visibility as hiding — Java four levels. Let be visibility: in increasing exposure (private most restrictive). Java symbols: public (all), protected (subclasses even across packages), package-private/default (same package only, no keyword), private (only the class). Mark fields private by default; expose behavior via public operations; use package-private for helpers shared inside a module; use protected only for genuine extension points meant for subclasses. Private is the most stringent.
A truth table helps:
| Modifier | Same class | Same package, not subclass | Subclass in other package | Anywhere |
|---|---|---|---|---|
private |
yes | no | no | no |
| package (default) | yes | yes | no | no |
protected |
yes | yes | yes | no |
public |
yes | yes | yes | yes |
Misconception correction — protected vs package. Students not listening difference protected package triggers correction protected hierarchy versus package within package is the moment recorded. Many learners conflate them. Protected is hierarchy-based sharing — it reaches across packages but only along inheritance lines. Package-private is locality-based sharing — it reaches every class in the same package but stops at the package boundary, even for subclasses. For cross-package subclass extension you need protected; for within-package cooperation you keep package-private. Which is more stringent and whether they are the same was the lecturer's repeated check; answer: private most stringent, then package and protected differ in cross-package versus hierarchy dimension.
Guidance: start with private fields and public behaviour; downgrade to package or protected only when you can state the intended sharing precisely. Excess protected weakens encapsulation along inheritance.
Example — Choosing visibility. Class BankAccount has - balance: Money private, ~ addEntry(e): void package-private for helpers in banking package to batch post entries, # applyInterest(): void protected for SavingsAccount in another package to extend, + getBalance(): Money public. Callers see only getBalance; package helpers can batch; subclass can hook interest; nobody can directly set balance. That is the contract.
Pitfall — Leaky internals. A common slip is making collection fields public or returning the live collection via a getter. Callers then manipulate internals directly — content coupling via visibility. Return a copy or an unmodifiable view, or expose only addItem / removeItem operations that preserve invariants.
Recap. Cohesion asks "do methods and data belong to one purpose?" Visibility enforces the answer. Keep internals private, share inside the package with package-private, extend across packages with protected sparingly, and treat high cohesion as the reason many small classes are acceptable.
12.7 Corollaries and General Design Rules Derived from the Axioms
12.7.1 The Set of Six Corollaries
All six corollaries that the lecture will cover are said to be based on the two axioms of independence and information. They are presented as different wordings on content but one in meaning, all dependent on those axioms. The summary sketch is: axioms two give corollaries one, two, three, all dependent on the axioms, and corollary four depends on others as well. The exact count beyond six is not enumerated separately; the set of six is the organizing claim.
12.7.2 Corollary One — Uncoupled Design with Less Information Content
A statement close to the axiom itself is highlighted as Corollary One: use an uncoupled design with less information content. In other words, low coupling together with less information held or exchanged gives highly cohesive things. The material explicitly links this corollary to low coupling on the independence side and less information on the cohesion side, so that high cohesion and low coupling appear together.
12.7.3 Corollary Two — Single Purpose
Corollary Two is named as single purpose, already introduced earlier. Methods or classes should be single-purpose. That phrase is the wording used for the cohesion consequence: a method that serves multiple functions or a class with unrelated responsibilities violates the information axiom. The recommended response is to split such a class into two or more classes and move functions to new classes.
12.7.4 Remaining Corollaries and Design Rules Gathered Under Them
The spoken source gathers a larger family of practical rules that function as the remaining corollaries, even when the numbering is not always spoken aloud. Together they are:
- Large numbers of simpler classes are fine — keep things simple even if it means more classes, because smaller single-purpose classes are easier to understand and maintain.
- Strong mapping from problem-domain objects to solution objects — the design classes should track the entities found in analysis, and refinement keeps that mapping tight.
- Reuse through interfaces and standard components — move commonalities into interfaces or abstract classes so communities of behaviour are taken out and put into reusable forms.
- Design for inheritance — move common behaviour to super classes, create generalization to specialization structures, and challenge any inheritance relationship to ensure it supports only genuine generalization to specialization.
- Standardization and design for interchangeability — use standard solutions so parts can be reused.
- Avoidance of recomputation and redundancy — by creating derived attributes and triggers where something is often computed, and by not repeating what is already computed.
- Consideration of execution order semantics and frequent use of methods, and avoidance of excessive reuse that breaks the single-purpose rule.
These are presented as the "different design rules or axioms that have come from these corollaries" that the class should be able to state: highly cohesive objects with low coupling, each class single-purpose, large number of simpler classes, mapping strongly from objects in the problem domain to implementation, promotion of standardization by reusing classes and building standard interfaces, and designing for inheritance by moving common behaviour to super classes.
12.7.5 Student Questions and Answers
Q: What have you learned about designing through these corollaries and design rules? A: One response summarized learning as coupling, cohesion, inheritance, standards, and the grasp of the concept. The speaker affirmed that view and added that "design for reuse" is a good way to capture the whole set — highly cohesive objects with low coupling, single purpose, many simple classes, strong domain mapping, standardization through reusable interfaces and classes, and inheritance with common behaviour in super classes.
12.7.6 Industry Applications
Real-world: In refactoring reviews, a class found to carry two unrelated purposes is split into two single-purpose classes, and duplicated fields are pulled up into a shared super class, which is a direct application of these corollaries.
Why six? The number is a pedagogical grouping: each corollary views the same two axioms through a different practical lens — coupling, information, purpose, size, mapping, reuse, inheritance, standardization. They are not independent theorems; they phrase one underlying idea ("high cohesion and low coupling via minimal exposed information") for different design decisions. Axioms two give corollaries one, two, three, all dependent on the axioms, and corollary four depends on others as well.
Corollary 1 — Uncoupled design with less information content. Keep designs uncoupled and information-lean. Practically: pass the smallest data that fulfills the contract; keep each class's state limited to its single purpose. Highly cohesive objects with low coupling, each class single-purpose is the paired phrase. Use an uncoupled design with less information content is the exact wording.
Corollary 2 — Single purpose. One class, one responsibility area. Also known as cohesion at the class level and as SRP (Single-Responsibility Principle). A method that carries multiple functions should not be done, and a class that loses focus should be challenged. Single purpose means single responsibility area, not minimal size.
Split example — Single purpose in action. OrderProcessor with methods calculateTotal(), printInvoice(), sendEmail() mixes pricing, formatting, and messaging. After applying corollary 2, you get PricingEngine, InvoiceFormatter, EmailSender each with one purpose. Each becomes testable alone, and a change to email templates no longer forces retesting of pricing logic. This is the split that the lecture recommends: if clumsy classes exist or unrelated data appears together, break them into two or more classes.
Remaining corollaries gathered as practical rules. The lecture gathers under remaining corollaries:
- Large numbers of simpler classes are fine — keep things simple even if it means more classes.
- Strong mapping from problem-domain objects to solution objects — keep that mapping tight through refinement.
- Reuse through interfaces and standard components — move commonalities into interfaces or abstract classes.
- Design for inheritance — move common behaviour to super classes, challenge any inheritance to ensure genuine generalization to specialization.
- Standardization and design for interchangeability — use standard solutions so parts can be reused.
- Avoidance of recomputation and redundancy — by creating derived attributes and triggers where something is often computed.
- Consideration of execution order semantics and frequent use of methods, and avoidance of excessive reuse that breaks single-purpose.
These are presented as the "different design rules or axioms that have come from these corollaries."
Visual one-liner: imagine a scorecard with six rows (high cohesion/low coupling, single-purpose, many simple classes, strong domain mapping, reuse/standardize, design for inheritance without excessive reuse). A design that scores well on all six fulfills the two axioms.
Trace — Pulling common behavior up. Two staff types share name, employeeId, department, salary but differ in teachingLoad vs shift. Create parent Employee holding the four common fields and getAnnualCost(). Children Faculty and OperationsStaff hold only their differing fields. Duplicated fields are pulled up into a shared super class, which is a direct application of design for inheritance and single purpose.
Pitfall — Reading corollaries as checklist ticks. The corollaries overlap; ticking them separately without seeing the unity leads to shallow compliance ("we have an interface, so we are standardized"). Ask always: does this decision reduce information carried and dependencies needed?
Recap — Design for reuse as the shortcut phrase. Highly cohesive objects with low coupling, single purpose, many simple classes, strong domain mapping, standardization through reusable interfaces and classes, and inheritance with common behaviour in super classes — that list, summarized as "design for reuse," closes the loop from axioms to practice.
12.8 Design Strategies — Strong Domain Mapping, Iterative Refinement, and Standardization
12.8.1 Cross-Cutting Alignment with Domain and Implementation
Several higher-level strategies are woven across the corollaries as ways any design can be approached. The first is strong mapping: there is a strong mapping across the whole approach because everything is based on the same model. The same notion of objects and methods is used everywhere, so analysis, design, and implementation speak the same language.
A second is iterative refinement. As understanding improves, the team keeps refining what has been done. The spoken source notes that iterative developments are more popular precisely because that mapping is strong: when you repeatedly do something, you do it in a better manner. Consistent modeling language makes repeated improvement practical.
12.8.2 Standardization as a Design Strategy
The next approach is standardization when learning a particular process. Standard solutions are collections of problem and solution. The everyday illustration offered is a port standard: USB is a standard port, and Type-C is a standard port nowadays, so every device can be connected through it because everyone follows it, which simplifies life for everything.
The software parallel is drawn immediately: for different components in software, a login and logout module is required by all applications. If that module is built once so that it logs in and out consistently and put in one module that everyone can use, that is very good. Industries pursue the same aim through ISO standards or ISI marks and through designing interchangeable components, so existing classes and components can be used without rebuilding and products can be built easily.
12.8.3 Patterns as Standard Solutions
Building on that idea, design patterns are presented as a good way to capture design knowledge, document it, store it in a repository, and reuse it in different applications. Patterns are described as standard solutions that should be reused in multiple places. Reuse in multiple places then improves productivity, and the colour the speaker used earlier for design with inheritance is tied back here: the same drive for reuse connects to inheritance and to patterns.
12.8.4 Student Questions and Answers
Q: Why emphasize standards like USB or ISO when we are discussing class design? A: Because the same principle governs both. A standard interface reduces the number of distinct contracts a team must learn and test, so a class or component that delivers a standard service, such as authentication, can be reused across many systems rather than rebuilt each time.
12.8.5 Industry Applications
Real-world: Product teams maintain a shared authentication component used by many applications and a pattern repository from which teams pick a known solution before sketching a new one.
Hook — Why does iterative development work? Because strong mapping keeps the same names across analysis, design, and code. When you repeat work using the same vocabulary, each pass gets better — the same reason revising an essay improves it more if you keep the characters' names.
Strong mapping in practice. There is a strong mapping across the whole approach because everything is based on the same model. The same notion of objects and methods is used everywhere, so analysis, design, and implementation speak the same language. Keep domain terms alive in code — Product, Sale, Customer appear in requirements, in domain model, in design class diagrams, and in domain.* packages. Iterative developments are more popular precisely because that mapping is strong.
Standard solutions reduce distinct contracts. Standard solutions are collections of problem and solution. USB is a standard port, and Type-C is a standard port nowadays, so every device can be connected through it because everyone follows it. USB Type-C standard port analogy for software standardization interchangeable components ISO ISI is the lecture's chosen analogy. For different components in software, a login and logout module is required by all applications. If that module is built once so that it logs in and out consistently and put in one module that everyone can use, that is very good. Industries pursue the same aim through ISO standards or ISI marks and through designing interchangeable components.
Example — Standard auth component. Build AuthService with interface authenticate(userId, credential): AuthToken and logout(token). Package it as techservices.security. Every application — web, mobile, batch — calls the same interface. When the password rule changes, one component changes, all callers stay compatible. That is interchangeability at the design level, analogous to swapping a USB-A cable for USB-C via an adapter that still respects the USB protocol.
Patterns as the repository. Design patterns are a good way to capture design knowledge, document it, store it in a repository, and reuse it in different applications. Patterns are standard solutions that should be reused in multiple places. Reuse in multiple places then improves productivity. The same drive for reuse connects to inheritance and to patterns — both standardize a proven shape.
Framing: treat inheritance reuse and pattern reuse as two scales of the same standardization aim — inheritance standardizes within a hierarchy, patterns standardize across systems.
Pitfall — Standards without adoption. Declaring a standard login module that nobody uses (because each team reinvents theirs) yields no benefit. Standardization succeeds only when the module is the easiest path — good docs, single import, versioned contract — so teams naturally choose it.
Recap. Strong mapping lets you refine iteratively; standardization (USB, ISO, login modules, patterns) lets you reuse instead of rebuild. Both are strategies for keeping the axioms satisfied at scale.
12.9 Design Heuristics and Pitfalls
12.9.1 Practical Eye on Class Roles and Size
A dedicated cluster of heuristics is offered as a careful eye to keep on class design. For any class, its role in the system should be challenged. If an object loses focus and is not single-purpose, the design should be modified and some functions moved to new classes. The class is allowed to be split: if clumsy classes exist or unrelated data appears together, break them into two or more classes. Creating new classes beyond those thought of in analysis is explicitly allowed. The lecture adds that there is no end to learning design principles and rules.
12.9.2 When a Design Should Be Distrusted
A set of intuitive distrust signals is listed. Not only for software, but for any design:
- Avoid recomputation by creating derived attributes and triggers where a value is often computed.
- Avoid redundancy — do not keep doing repeatedly what has already been done.
- Consider execution-order semantics and frequent use of methods.
- If a design looks very messy, it should probably be redesigned; it is not good if it is too complex.
- If it is too big, that is also not a good design; if it is very small, that also raises a flag.
- If the designers themselves do not like their solution, it is possibly a bad design — the test phrased as "if we are not liking our solution, how would others like it."
- If something is not working, it is definitely bad; the first criterion is at least it should be working.
Each of these is presented as a practical corollary of the two axioms, stated in everyday form.
12.9.3 Connection to Graphical Modeling
The closing heuristic before the break is that design classes being discussed are business-level classes. Those business classes will interact with UI classes and with database classes. The whole collection will be tested continuously with use cases. The ultimate handling of inheritance and reuse relationships, and the decision to modify designs because classes look clumsy, leads directly into diagramming, which is why class diagrams and state transition diagrams are introduced next.
12.9.4 Industry Applications
Real-world: In code review a reviewer who cannot explain a class's single role in one sentence will ask for a split, and a module whose interaction diagram looks tangled is scheduled for redesign before further features are added.
Role test. For each class, write one sentence: "A is a ... that is responsible for ... and collaborates with ..." If the sentence needs "and" twice, or lists two unrelated collaborator groups, the class needs a split. Expect to invent new classes that never appeared in analysis — controllers, mappers, factories — when they earn a single purpose. There is no end to learning design principles and rules, and creating new classes beyond those thought of in analysis is explicitly allowed.
Example — Challenging a clumsy class. Review finds OrderWithHistoryAndEmail holding orderLines, historyLogs, smtpConfig and methods addItem(), archive(), sendConfirmation(). History and emailing change for different reasons than ordering. Split into Order, OrderHistory, and ConfirmationSender. Each new class is now cohesive, and reuse of mailing logic elsewhere becomes possible. If clumsy classes exist or unrelated data appears together, break them into two or more classes.
When to distrust a design — heuristics. If design looks messy, too complex, too big, very small, or designers dislike it, distrust redesign heuristic applies. More concretely:
- Avoid recomputation by creating derived attributes and triggers where a value is often computed (e.g., cache
totalonSale). - Avoid redundancy — do not keep doing repeatedly what has already been done.
- Consider execution-order semantics and frequent use of methods.
- If it is too big or very small, both raise a flag — size alone is not a metric without cohesion.
- If designers themselves do not like their solution, it is possibly a bad design.
- If something is not working, it is definitely bad; at least it should be working.
Each is an everyday form of the axioms.
Connection to graphical modeling. Design classes being discussed are business-level classes. Those business classes will interact with UI classes and with database classes. The whole collection will be tested continuously with use cases. The ultimate handling of inheritance and reuse relationships, and the decision to modify designs because classes look clumsy, leads directly into diagramming, which is why class diagrams and state transition diagrams are introduced next.
Real-world check: in review a reviewer who cannot explain a class's single role in one sentence will ask for a split, and a module whose interaction diagram looks tangled is scheduled for redesign before further features are added. The "messy diagram" test predicts defect density better than raw line counts. If design looks messy too complex too big very small or designers dislike it distrust redesign is the applied rule.
Recap. Challenge every class's role, split clumsy ones, watch recomputation and redundancy, trust the smell of mess or dislike, and then visualize the result. Diagrams are how you make the heuristics discussable.
12.10 Class Diagram Notation — Classes, Attributes, Methods, and Interfaces
12.10.1 Why Class Diagrams Are Mandatory
Designs must be converted into UML diagrams as class diagrams or state transition diagrams so they can be represented and discussed. Among those, class diagrams are described as so fundamental to object-oriented design that without a class diagram a design cannot be represented. They are the core and mandatory way to represent a design. Once a complete set of diagrams exists, it can be converted into any programming language.
12.10.2 Class Box Structure and Visibility
A class is drawn as a rectangle with compartments for the class name, for attributes, and for operations. Visibility is shown on each attribute and method as public, private, protected, or package. The speaker notes that visibility has already been introduced and repeats that private is the most stringent.
An illustrative class used in the lecture is a Circle. Its radius and its center as a point, typed as double and Point, and its operations for area and circumference typed as double, with setters such as setRadius and setCenter, are described as candidates for that notation. Initial values can be placed with an equals sign, and each member is shown as name colon type, with operations shown as name parentheses parameters colon return type. Comments note that this is the main building block for any object-oriented program, repeated for emphasis.
12.10.3 Interface Notation and Components
The difference between an interface and a class notation is that they look the same except that an interface is marked with a stereotype such as interface. In an interface all methods originally have no implementations, though nowadays some implementations are also allowed. In that text, contents inside curly braces denote constraints.
A component is drawn as a rectangle with two small boxes on the side. A component is a collection of classes and is described as a physical component or module. Logically, components are equal to packages made in the design.
A deployment diagram shows different servers and different clients or different buildings over which the components sit. They are rendered as cuboids, as boxes that suggest physical elements. A comment is shown as a folded rectangle.
12.10.4 Industry Applications
Real-world: Teams deliver a design review package that starts with the complete class diagram and ends with component and deployment diagrams, because that set is the shared contract for implementation.
12.10.5 Exam Notes
Exam note: In the final exam a complete class diagram is expected for the system under design. This is flagged as the main building block, so notation for attributes, methods, visibility, and interface versus class must be ready.
Hook — Why a diagram is not extra work. Code shows one class at a time; a class diagram shows many classes and their relationships on one page. That overview lets a team spot a cycle, a missing generalization, or a content-coupled link before anyone writes 500 lines that later must be moved. Class diagrams are so fundamental to object-oriented design that without a class diagram a design cannot be represented.
Design class diagram vs domain model. Both use the same box-and-line notation, but with different intent. A domain model shows real-world concepts and optional associations to understand the problem; a Design Class Diagram (DCD) shows software classes with visibility, parameter types, and navigation arrows as a blueprint for code. In the UP, the set of DCDs plus package and interaction diagrams forms the Design Model. Once a complete set of diagrams exists, it can be converted into any programming language.
Box anatomy. Top compartment: class name (optionally «interface»). Middle: attributes as visibility name : Type = default {properties}. Bottom: operations as visibility name(params): ReturnType {properties}. Visibility marks: + public, - private, # protected, ~ package. An ellipsis ... indicates omitted members. Example full attribute: - radius : double = 1.0 ; operation: + getArea(): double. Initial values with =, derived attributes with /, constraints with {}.
Worked example — Circle. Circle class with radius center Point and operations area circumference setRadius is the lecture's core illustration. Draw a class Circle with attributes - radius : double = 1.0 and - center : Point and operations + getArea(): double, + getCircumference(): double, + setRadius(r: double), + setCenter(p: Point). Implementations: , . Compute for : , (equal only because ). For : , . The diagram plus these implementations map directly to Java:
public class Circle {
private double radius = 1.0;
private Point center;
public double getArea() { return Math.PI * radius * radius; }
public double getCircumference() { return 2 * Math.PI * radius; }
}
Each attribute line became a field; each operation a method with the same signature and visibility.
Initial values (= 1.0), derived attributes (/area), and constraints ({radius > 0}) can be added in {}. The "..." tells readers the list is partial, not that the class has only those members.
Interface vs component vs deployment. Interface «interface» Timer { getTime(): Time } — an abstract contract drawn like a class but marked «interface»; nowadays it may carry default implementations. Component — a replaceable module grouping classes, drawn as a rectangle with two tabs on the left edge, equal logically to packages made in the design. Deployment node — a physical host (server, device) drawn as a cuboid, with components placed on nodes. A comment (folded rectangle) attaches explanatory text with a dashed line. Constraint text lives inside {} near the constrained element (e.g., {size >= 0} on a stack).
Pitfall — Mixing logical and physical. Do not place a database as a layer below packages. Model the need for persistence as a Persistence component or domain.inventory sub-domain in the logical view; model MySQL as a node with a Database artifact in the deployment view.
Recap. The class box with visibility, types, initial values, and operation signatures is the main building block for any object-oriented program. Practice the Circle until you can draw it from memory, then add «interface», component tabs, cuboids, {constraints}, and folded comments around it.
12.11 Relationships Between Classes — Association, Aggregation, Composition, Generalization, and Dependency
12.11.1 From CRC Responsibilities to Relationship Types
CRC cards inspire the search, but the goal is to convert those responsibilities into relationships. When inheritance is used, inheritance and association links are the first to place, and composition relationships are added next. The main relationships named are composition, inheritance, aggregation, and the more general category of association, with dependency also called the users relationship.
The practical advice is that if the relationship is unknown, keep it as a simple association with a plain line. More specialized relationships refine that line.
12.11.2 Inheritance and Realization
Generalization as inheritance is the is-a or kind-of relationship. Examples drawn from the real world are the is-a links in a staffing model such as an employee hierarchy. A difference too is stated between inheritance and aggregation: inheritance is about containment versus specialization — one is a has-a containment relationship, the other is a specialization relationship. The speaker phrases it as inheritance being very well explained through the generalization to specialization relationship.
The visual notation for generalization is an unfilled arrow, a single line to an open triangle. When an interface is realized or inherited from, a dotted line with an unfilled or open arrow is used, so interfaces are realized rather than simply extended with a solid line. The text describes this as an unfilled arrow, arrow, open arrow — the intent is the standard UML realization arrow.
12.11.3 Aggregation and Composition — The Has-A Family
Aggregation and composition are described as very similar, both has-a relationships, and people often ask for the difference. Composition is the stronger relationship. The lecture works through examples: campaign and advertisement where campaign is made up of advertisements, class and student as an aggregation relationship, and meal and its ingredients as a strong composition case that is described as a field diagram. The phrasing used is that composition is stronger while aggregation is a lighter relationship. Constraints, where they apply, are usually put in curly braces.
For design guidance with generalization and specialization, the step is to list commonalities and differences for two types that share much. Common attributes and behaviour, and also behaviour that differs, are examined. Two types of staffs are offered as a running illustration: what are their differences, and those are listed and put into two different classes that share a common parent through inheritance. The core teaching is to create a common parent and put common elements into that single class, looking in the problem statement for opportunities to generalize.
12.11.4 Dependency or Uses and Simple Association
A dependency or uses relationship is about the client and supplier where the full class is being used. A class uses another class as a member variable or as a parameter to a method, so a lot of dependence exists: an object is created, all information about it is obtained, and the client does not have semantic knowledge of the supplier in the realization sense, it is just using it. The notation named for uses is a dotted line.
A simple association is the case where both classes use each other but there is no owner and no client or server asymmetry. The running illustration is manager and swipe card: the manager uses the swipe card and the swipe card uses the manager when the card is swiped through the manager to log in, so both sides need each other. That is kept as a simple association with a plain line in both directions when no ownership semantics exists.
The summary of notation offered for the main relationships is: generalization as inheritance shown by a single line with a hollow triangle, aggregation with a diamond, composition with a filled diamond, dependency or uses with a dotted arrow, and realization of an interface with a dotted line and open arrow. The lecture notes that an interface is realized, a class implements it, and dependencies also appear as uses.
12.11.5 Student Questions and Answers
Q: What is the difference between aggregation and composition, and how do we know which to use? A: Both are has-a relationships. Aggregation is the lighter has-a, such as a class that has students where the students can live without the class. Composition is the stronger has-a, such as a meal that has ingredients where the ingredients as a meal assembly do not stand apart in the same way. Look at whether the part can survive meaningfully without the whole. If the life of the part is strongly bound to the whole, use composition with a filled diamond; otherwise aggregation with an open diamond is enough.
Q: When we have generalization to specialization, how should we handle attributes? A: List what is common and what differs between the candidate subclasses. Put all common attributes and common behaviour into the single parent class. Keep only the differences in each child. Then repeat the search in the problem statement for other opportunities to create such hierarchies so that more reuse is captured through inheritance.
12.11.6 Industry Applications
Real-world: A product team models a catalog as a composition over its items and models customer types as a generalization hierarchy so that shared validation moves to the common parent.
From responsibilities to lines. A CRC note "Sale collaborates with SalesLineItem to know total" becomes an association; "Board contains Squares and manages their lifecycle" becomes a composition; "SavingsAccount is-a Account" becomes a generalization. Start with a plain association between any two collaborating classes; then ask: is there a whole-part lifetime rule? is there an is-a rule? is there just a uses dependency via a parameter? The answer sharpens the line. Inheritance and association links are the first to place, and composition relationships are added next.
Notation — generalization vs realization. Generalization (inheritance): solid line with hollow triangle pointing to the superclass (e.g., Manager → Employee) — the is-a or kind-of relationship. Realization (interface): dashed line with hollow triangle pointing to «interface» (e.g., Clock – – → «interface» Timer) — a class realizes an interface. In both, the arrow points to the more general classifier. Unfilled arrow, single line to open triangle is the generalization notation; dotted line with open arrow is realization.
Terminology contrast — aggregation versus generalization. Aggregation versus composition contrast lighter has-a versus stronger has-a filled diamond versus open diamond is the core warning, but the deeper confusion is has-a vs is-a. Aggregation/composition are has-a / whole-part (a student has-a address; a board has squares). Generalization is is-a / kind-of (a manager is-a employee). Mixing them — treating "has-a invoice" as inheritance — breaks substitutability. List what is common and what differs; common goes to parent, differences stay in children.
Aggregation vs composition — lifetime and ownership. Aggregation (open diamond ◇ on the whole): part can exist independently of the whole. Composition (filled diamond ◆): part's lifetime is tied to the composite; the composite creates and deletes its parts; a part belongs to at most one composite at a time. Constraints usually put in curly braces. Campaign made up of advertisements as composition and class student aggregation is the contrast pair; meal and its ingredients as strong composition is the stronger illustration.
Example — Catalog of distinctions. Campaign ◆ advertisements (composition): if the campaign is cancelled, its advertisements as campaign-specific assets are discarded — the part does not outlive the whole. Class ◇ student (aggregation): a class has many students, but a student survives when the class ends. Meal ◆ ingredients (strong composition): the meal as an assembled plate owns its ingredient portions for that serving — discard the meal and the portions are gone. Apply the lifetime test: can the part meaningfully survive without the whole? If no, prefer composition with filled diamond; otherwise aggregation with open diamond is enough.
Design step for generalization from the staff illustration: list attributes name, employeeId, salary common to Manager and Clerk → move to parent Employee; keep teamSize, bonusPolicy in Manager and shift, hourlyRate in Clerk. Common attributes and behaviour, also behaviour that differs, examined for two types of staffs — that is the exercise.
Dependency as "uses". Dependency or uses relationship is about the client and supplier where the full class is being used. A class uses another class as a member variable or as a parameter to a method, so a lot of dependence exists: an object is created, all information about it is obtained. Notation for uses is a dotted line (dependency arrow). Simple association is where both classes use each other but there is no owner — manager and swipe card simple association both use each other without owner is the running illustration: manager uses swipe card and swipe card uses manager when card is swiped through manager to log in, kept as simple association with plain line both directions. Generalization as inheritance shown by single line with hollow triangle, aggregation with diamond, composition with filled diamond, dependency or uses with dotted arrow, realization with dotted line and open arrow is the notation summary.
Example — Manager and swipe card. Neither owns the other; both need each other for the login use case. Model as a plain bidirectional association Manager — SwipeCard (optionally with role names holder and credential). By contrast, Sale.updatePriceFor(ProductDescription d) where Sale receives a ProductDescription as a parameter and calls d.getPrice() is a dependency: Sale - - → ProductDescription via parameter visibility, not a permanent field.
Quick reference repeated for study: generalization hollow triangle solid, realization hollow triangle dashed, aggregation open diamond, composition filled diamond, dependency dashed arrow, simple association plain line.
Pitfall — Diamonds everywhere. Beginners add diamonds to every association. Use a plain line when ownership is not the point. Add a diamond only when you can state the lifecycle rule that justifies it.
12.12 Multiplicity, Constraints, Components, and Deployment
12.12.1 Multiplicity Identification
Associations are augmented with multiplicity and roles. All kinds of cardinalities are possible between any two objects: one-to-one, one-to-many, many-to-many, and so on, either named or given by roles.
The method taught for identifying cardinality is to hold one side as one and move the other: keep one as one and vary the other to see whether it is one or many. The example used is an instructor and a course: one instructor and how many students or courses can be involved. On the course side the question is whether a course is taught by one instructor or by many instructors, so whether the relationship is one-to-one or one-to-many is decided by holding one end at one and watching the other.
Role naming or explicit naming at the ends of an association is offered as an alternative to relying only on multiplicity numbers.
12.12.2 Constraints, Comments, Components, and Deployment Recap
Constraints that restrict a relationship or attribute are written in curly braces. Comments are shown as folded rectangles.
The component-to-deployment connection is then summarized. Components as rectangles with small boxes are collections of classes and correspond logically to packages. Deployment diagrams then place those components on physical nodes — servers, clients, or buildings — drawn as cuboids. This is the final topology of the system. For interface versus class, the notation difference is the interface stereotype, and constraints can be attached wherever they are needed.
12.12.3 Student Questions and Answers
Q: How do we identify cardinality in a relationship? How do we know if it is one-to-one, one-to-many, or many-to-one? A: Hold one side as one and let the other vary. Ask whether the other side is one or many when the first is one. For an instructor teaching courses, hold one instructor as one and ask how many courses can be taught by that instructor. Then hold one course as one and ask how many instructors can teach it. The pair of answers gives the right multiplicity at the two ends.
12.12.4 Industry Applications
Real-world: An online enrollment model records that one instructor may teach many courses while one course may have many students, so the two associations carry different multiplicities that are decided by exactly this hold-one-fixed test.
Hold-one-fixed test. To decide multiplicity between and , ask two questions: "One , how many ?" and "One , how many ?" The pair of answers gives the two ends. All kinds of cardinalities are possible: one-to-one, one-to-many, many-to-many, either named or given by roles. Numbers use UML multiplicity: 1 (exactly one), 0..1 (optional), * or 0..* (zero or more), 1..* (one or more), n..m (range). Role naming at ends is alternative to numbers. Instructor course cardinality identified by holding one as one and varying the other is the method the lecture names.
Visual: draw a small table with rows for each question. For instructor–course: one instructor → many courses, so instructor end is 1, course end is *. One course → one instructor (if each section has one lead) or 1..* if team-taught — the business rule decides, which is why the test must be asked twice, not once.
Worked example — Instructor and course. Hold one instructor fixed. Can that instructor teach many courses over time? In a university, yes — so the instructor-to-course multiplicity at the course end is * (or 1..* if an active teaching requirement is assumed). Now hold one course fixed. Can one course be taught by many instructors? If team-teaching is allowed, the course-to-instructor end is 1..*; if each offering has exactly one lead, it is 1. So the association may be Instructor 1 — * Course or Instructor 1..* — * Course depending on policy. Document the assumption in a constraint {each offering has one lead} if you choose 1. This is the hold-one-as-one and vary the other technique.
Common error: reading multiplicity only in one direction. Always ask both ways; a one-to-many in one domain may be many-to-many in another.
Constraints and comments, components and deployment recap. Constraints that restrict a relationship or attribute are written in curly braces ({balance >= 0}, {ordered}). Comments are shown as folded rectangles with dashed lines. Components as rectangles with small boxes are collections of classes and correspond logically to packages. Deployment diagrams then place those components on physical nodes — servers, clients, or buildings — drawn as cuboids. This is the final topology. Interface versus class notation differs by «interface» stereotype, constraints attached wherever needed. Components equal packages deployed to nodes.
Pitfall — Mixing logical and physical. Do not place a database as a layer below packages. Model the need for persistence as a Persistence component or domain.inventory sub-domain in the logical view; model MySQL as a node with a Database artifact in the deployment view. Keeping views separate prevents layering confusion.
Recap. Multiplicity is decided by holding one side at one and varying the other, asking both directions. Record the policy as a constraint when it matters. Components group classes; deployment shows where components run as cuboids; package vs deployment is logical vs physical.
12.13 State, Activity, and Dynamic Behavior Diagrams
12.13.1 The Role of State Modelling
These diagrams represent the dynamic behaviour of objects. Where class diagrams show structure, state modeling shows how a particular object behaves through states over time. Attribute identification and method development help with this, especially with post-conditions. States are described as conditions a particular object satisfies during interaction for some amount of time. Once a method is executed or a condition becomes true, the object moves to another state. Semantics flow through such transitions, which are sometimes instantaneous while states themselves endure for a period.
These diagrams are also called state transition diagrams and they underpin activity diagrams. The lecture notes that activity diagrams use the notation of state transition diagrams and that they are very popular.
12.13.2 Notation — States, Events, Guards, and Actions
A state diagram for one object shows states with activities inside, at least the entry and exit actions and the actions performed while in the state. The transition between states has a trigger: some method is executed with parameters, or a condition becomes true under a guard condition that becomes active, causing the move from one particular state to the next. The initial state and the ready state are mentioned, and a stop event is used to reach the done or final state. The final state is reached when a condition becomes true.
A catalogue of event types is listed:
- A change event based on some condition becoming true as a guard.
- A signal event from outside where some signal arrives.
- A time event caused after some time has elapsed.
- A call event where some function or operation is called over the object.
Each carries the same idea: something happens, often with parameters or with a guard condition, and the transition fires.
12.13.3 Illustrations — ATM, Watch, Enrollment, and Employment
Concrete illustrations are used to make the notation concrete:
- For an ATM, the states include an off state, then a waiting or idle state, and if a customer arrives, a serving state. Within serving, ongoing actions are performed, and substates may be nested.
- For a smart watch, pressing a button causes a move from one state to the next, and various signals drive the watch through states.
- For a student, different states are entered as time events or when a step such as clearing an exam occurs.
- For an employee, joining puts the object in a probation state and after one year it becomes permanent — a time event with a guard on elapsed time.
These illustrations are described as practice material: look at various examples and learn the notations through them.
12.13.4 Nested States, Fork, and Join
Within a state, nested substates can be shown. Parallel behaviour is shown through a synchronization bar represented as fork and join. The bar allows concurrent activities to split and then rejoin. The lecture notes that this is shown as a concurrent example and that component diagrams can be shown as different packages alongside these dynamic diagrams, with final deployment diagrams tying everything together.
12.13.5 Student Questions and Answers
Q: How do we discover states for a particular object? A: Identify conditions an object satisfies for a period of time and look at post-conditions of attribute identification and method development. For each state note entry and exit actions and which event, guard, or time condition moves the object to the next state, and use fork and join where concurrent parts must be shown.
12.13.6 Industry Applications
Real-world: A payment service is modeled with states such as idle, authenticating, authorizing, and completed, with time events for timeouts and guard conditions on approval, so test cases follow directly from the transitions.
12.13.7 Exam Notes
Exam note: Be ready to draw a state or activity diagram for a small scenario such as an ATM, a smart watch, or a student or employee life cycle, showing states, guard conditions, entry and exit actions, and fork or join where concurrency is needed.
Structure vs behaviour. Class diagrams show structure; state modeling shows how a particular object behaves through states over time. States are conditions a particular object satisfies during interaction for some amount of time. Once a method is executed or a condition becomes true, the object moves to another state. State transition diagrams underpin activity diagrams and they are very popular. Attribute identification and method development help with this, especially with post-conditions. Semantics flow through transitions, which are sometimes instantaneous while states themselves endure for a period.
Think of a traffic light. Structure says "a Light has colors and timers." Behaviour says "a Light stays Red for 30s, then goes Green on timer, stays Green until a pedestrian button, then goes Yellow briefly, then Red." You need both views to build the controller correctly.
Transition syntax and event catalogue. Label a transition as event [guard] / action. Examples: pressButton / startTimer, after(1 year) [rating >= 4.0] / promote, when(balance < 0) / notify. A state box shows entry / ..., do / ..., exit / ... inside. Initial state is a filled circle, final is a bullseye, ready/done states are named intermediates. Four event types:
- change event — condition becoming true as a guard
- signal event — signal arrives from outside
- time event — after time has elapsed
- call event — operation is called over the object
Each carries the same idea: something happens, often with parameters or with a guard condition, and the transition fires. The final state is reached when a condition becomes true; stop event used to reach done.
Worked trace — ATM. ATM off waiting idle serving state with substates and fork join is the primary trace. Model one ATM object. States: Off (entry: powerOff), Idle (display "Insert card"), Serving (nested: ReadingCard, VerifyingPIN, Dispensing). Transitions: Off → Idle on powerOn. Idle → Serving on customerArrives. Serving.ReadingCard → VerifyingPIN on cardInserted. VerifyingPIN → Dispensing on verifyPIN [pinValid] / showMenu. VerifyingPIN → Idle on cancel or verifyPIN [not pinValid and retries < 3] / ejectCard. Dispensing → Idle on cashTaken or after(30s) / ejectCard. Nested substates let the Serving superstate handle a single cancel transition that applies to all inner states. That is the structure students should sketch for practice. Within serving, ongoing actions are performed, and substates may be nested.
Worked traces — Watch, student, employee. Smart watch button press signal event driving state transitions: DisplayTime → SetTime on buttonPress [long], SetTime → DisplayTime on buttonPress [short] / save. Student clearing exam and employee probation to permanent time event after one year: Applicant → Enrolled on clearExam [passed], Enrolled → Graduated on when(credits >= required). Employee: Probation → Permanent on after(1 year) [performance = satisfactory] with entry action grantBenefits in Permanent. Student different states are entered as time events or when a step such as clearing an exam occurs. These use change, signal, and time events respectively — label each transition accordingly for exam marks.
To discover states, list conditions that hold for a duration ("waiting for card," "on probation") versus instantaneous events ("card inserted," "year elapsed"). Post-conditions of methods ("post: balance updated") often reveal a new state.
Hierarchy and concurrency. Within a state, nested substates can be shown. Parallel behaviour is shown through a synchronization bar represented as fork and join. The bar allows concurrent activities to split and then rejoin. Fork splits one thread into two concurrent paths; join waits for both to finish before continuing. In activity diagrams the same bar expresses parallel workflows. Component diagrams can be shown as different packages alongside these dynamic diagrams.
Visual: a state Serving containing three inner states arranged vertically; a single arrow cancel / eject leaves the outer border. Below, a fork bar splits into "print receipt" and "dispense cash" lanes, then a join bar merges before returning to Idle.
Pitfall — State explosion. Listing every attribute combination as a state yields dozens of meaningless states. Keep states at the level of meaningful modes a stakeholder would name ("idle, serving, off"), not at the level of every field value.
Recap. State diagrams show one object's modes, entry/exit actions, and transitions labeled event [guard] / action across four event types, with nested states and fork/join for hierarchy and concurrency. They underpin activity diagrams and drive test cases directly from transitions.
12.14 Process for Building Models and Next Steps
12.14.1 How Modelling Is Done
The process for making models or diagrams is listed as starting with some brainstorming, then sketching, modifying, organizing the different parts, specifying the details about the diagrams, and then integrating them. After integration they are verified and validated, and a prototype is created, tested, and evaluated. That is the way different models are created. The team is then asked to proceed with practice on various techniques and to work on the diagrams, with encouragement to try them once.
12.14.2 Forward Plan for the Course
Two more sessions will focus on design patterns by Gamma and colleagues, covering the 23 patterns in three categories — creational, behavioural, and structural — so that standard solutions through standard problems are studied. The last session will talk about metrics so that the treatment of OOD is completed. That plan is stated as the way the remaining study will complete the topic before moving on.
12.14.3 Industry Applications
Real-world: Before coding a new workflow, a team will sketch a state model and a component model, review them, and prototype the most uncertain interaction, which is the build-model habit taught here.
Model-building pipeline. The process for making models or diagrams is starting with some brainstorming, then sketching, modifying, organizing the different parts, specifying the details about the diagrams, and then integrating them. After integration they are verified and validated, and a prototype is created, tested, and evaluated. That is the way different models are created.
1) Brainstorm: list candidate classes, responsibilities, and key collaborations (CRC). 2) Sketch: draw a rough class and interaction sketch on a wall. 3) Modify & organize: split clumsy classes, enforce visibility, add multiplicities and constraints. 4) Specify: add types, operation signatures, guards. 5) Integrate: ensure class, sequence, and state views agree. 6) Verify/validate: check against use cases and well-formedness rules; walk through a use case trace. 7) Prototype, test, evaluate: implement the uncertain interaction first as an executable spike to learn.
Working this pipeline in iterations prevents big-bang modeling. One iteration might complete steps 1-5 for one use case; the next refines based on test feedback. Before coding a new workflow, a team will sketch a state model and a component model, review them, and prototype the most uncertain interaction, which is the build-model habit taught here.
Forward plan — patterns and metrics. Two more sessions will focus on design patterns by Gamma and colleagues, covering the 23 patterns in three categories — creational, behavioural, and structural — so that standard solutions through standard problems are studied. Gamma et al., the Gang of Four, 23 patterns in three categories creational behavioural structural is the precise reference. The last session will talk about metrics so that the treatment of OOD is completed. That plan is stated as the way the remaining study will complete the topic.
Spike example. Uncertain about integrating PaymentGateway with timeout handling? Build a tiny prototype with Payment states authorizing → authorized / timeout → failed and a stub gateway that randomly delays. Testing the prototype reveals that a after(2s) transition is needed — a design insight cheaper to learn before wiring the full system.
Recap + Bridge to course end. Brainstorm, sketch, organize, specify, integrate, verify, prototype — that loop is the habit. Patterns next give you a vocabulary of proven loops; metrics last give you a way to measure whether the loop produced a good design.
Exam Guidance Summary
The speaker ties design reasoning explicitly to examination expectations. The final exam will require a complete class diagram for the system under design. That makes class diagram notation — class boxes, attributes as name-colon-type with initial values, operations as name-parentheses-colon-return type, visibility levels public, private, protected, package, interfaces with the interface stereotype, components as rectangles with small boxes, deployment nodes as cuboids, constraints in curly braces, and comments as folded rectangles — a mandatory revision set. State transition, activity, component, and deployment diagrams are also singled out as diagrams to practice, because they cover the structural and dynamic contract of the system. The design axioms and corollaries are flagged as the source for why a particular decomposition was chosen, so being able to state the two axioms, the six corollaries, and the practical rules such as single purpose, many small classes, strong domain mapping, standardization, and design for inheritance is directly examinable as conceptual reasoning.
For metrics, the lecture points to the final session where depth of inheritance tree and lack of cohesion of methods and similar measures will be used to judge whether a design is good. Familiarity with those names is the current expectation; calculation detail will follow in that session.
Across sections, design for reuse and design through interfaces is repeatedly marked as important, along with the advice to minimize coupling toward data coupling, to hide information through the most stringent visibility that still allows needed access, and to prefer more inheritance through genuine generalization to specialization rather than ad hoc sharing.
Exam note: Final exam requires complete class diagram for system under design — class boxes, attributes as name-colon-type with initial values, operations as name-parentheses-colon-return type, visibility levels public, private, protected, package, interfaces with interface stereotype, components as rectangles with small boxes, deployment nodes as cuboids, constraints in curly braces, and comments as folded rectangles. State transition, activity, component, and deployment diagrams are also required; axioms and corollaries provide the why. Practice drawing the Circle class and one ATM-style state machine with guards and fork/join, and be able to list the coupling order content > common > control > stamp > data.
Key Industry Applications
- Use of patterns as existing good solutions: Every team is encouraged to learn from patterns rather than inventing a design from nothing, because patterns already document a tested problem and solution pair.
- CRC cards as a lightweight design learning tool: Writing responsibility and collaborator cards bridges the move from analysis objects to software objects.
- Modules, components, and packages as ownership boundaries: A system is split into components that own responsibilities, implemented as packages of classes, mirroring how product teams split work and ship libraries.
- Low coupling in service interfaces: Direct internal field access is refactored away from content-like coupling toward data coupling where only needed simple data items are passed, and message frequency and complexity are kept low.
- Information hiding by visibility: Private is treated as the default for internals, package visibility for package-local helpers, and protected only for intended subclass extension across packages.
- Strong domain mapping: The same object vocabulary runs from analysis through design to implementation, which is why iterative refinement works well in products built around a shared domain model.
- Standardization for reuse: Shared components such as login or logout modules, standard ports such as USB or Type-C, and industry marks such as ISO or ISI illustrate the benefit of interchangeable parts that are built once and reused everywhere.
- Design for inheritance: Common behaviour is moved to super classes through genuine generalization, reducing duplication while keeping each specialization single-purpose.
- Metrics-driven review: Depth of inheritance, lack of cohesion, and related coupling measures are the industry's check that a design labelled low-coupled and highly cohesive actually measures that way.
- State-driven behaviour: Workflow systems such as ATMs, smart watches, student enrollment, and employee probation are modeled with states, guards, time events, and fork or join so that test cases follow from the diagram and the final deployment topology is shown explicitly before coding.
Real-world tie: Graphical modeling pipeline — brainstorm, sketch, organize, specify, integrate, verify, prototype — is the daily habit that turns the axioms into ship-ready models, as noted in the process section.
OODAP Lecture 12 notes · Object Oriented Design Principles and UML Modeling
Sections Breakdown
Transition from analysis domain objects to design software objects via modules, components and packages, using CRC and patterns.
Occam's Razor guides simplicity via decomposition, reuse and low coupling while trading class count vs integration.
Engineering reasoning via axiom/theorem/corollary chain and formal Z notation to justify design choices.
Independence (low coupling) and Information (high cohesion) axioms linked via highly cohesive -> less information -> lower coupling and measured by DIT/LCOM.
Coupling spectrum content/common/control/stamp/data plus interaction vs inheritance coupling and tight coupling reduction.
High cohesion as single purpose plus Java visibility private/package/protected/public and hiding via encapsulation.
Six corollaries: uncoupled/lean, single purpose, many small classes, strong mapping, reuse/interfaces, inheritance, standardization, avoid redundancy.
Strong domain mapping, iterative refinement and standardization via USB/Type-C and patterns as reusable solutions.
Heuristics to challenge class roles, split clumsy classes, watch recomputation/redundancy and distrust messy/too-big/too-small designs.
Mandatory DCD notation: class boxes, attributes, operations, visibility, Circle example, interface, component, deployment, constraints.
Association, aggregation/composition has-a, generalization is-a, dependency uses, realization and swipe-card/manager examples.
Multiplicity via hold-one-fixed test with instructor-course, plus constraints, comments, components and deployment nodes.
Dynamic behaviour via states, four event types, guards/actions, ATM/watch/student/employee traces and fork/join.
Model pipeline brainstorm-sketch-organize-specify-integrate-verify-prototype and forward plan to 23 GoF patterns and metrics.
Appendix carried through with light enrichment.
Appendix carried through with light enrichment.
Exam Revision Notes
Below is the distilled, exam-ready core. Every entry comes from the full explanation above. Use this section for rapid review; return to the main notes when a point needs more context.
From Analysis to Design — Modules, Components, and Packages
Must-know: Analysis maps what exists; design maps how to build with modules/packages while preserving domain vocabulary.
Top pitfall: Copying analysis one-to-one or inventing a class per method.
Self-check: What three views does module/component/package represent?
Connects to: 12.2, 12.11
Fundamental Design Goals — Simplicity and Occam's Razor
Must-know: Occam's Razor: prefer simpler design that achieves the aim via decompose, reuse, low dependence.
Top pitfall: Hiding complexity in a God Util class.
Self-check: Name one handle for simplicity and its trade-off.
Connects to: 12.4, 12.5
Reasoning About Design — Axioms, Theorems, and Corollaries
Must-know: Axiom (accepted), theorem (derived), corollary (specific rule) chain justifies why a method lives where it does; Z notation formalizes it.
Top pitfall: Copying one author's layout without re-deriving.
Self-check: Which level — axiom, theorem, corollary — is most specific?
Connects to: 12.4, 12.7
The Two Design Axioms — Independence and Information
Must-know: Independence axiom = low coupling; Information axiom = high cohesion; highly cohesive -> less information -> lower coupling.
Top pitfall: Counting only calls and ignoring data richness.
Self-check: Map each axiom to coupling or cohesion.
Connects to: 12.5, 12.6
Coupling in Depth — Types, Measures, and Desirable Levels
Must-know: Coupling grows with methods/attributes touched plus data richness; spectrum content>common>control>stamp>data; interaction minimized, inheritance pursued genuinely.
Top pitfall: Treating stamp as data; sharing two fields but adding unrelated methods.
Self-check: Which coupling is preferred: stamp or data?
Connects to: 12.6, 12.7
Cohesion, Information Hiding, and Visibility
Must-know: Cohesion is single-purpose focus; hiding via private < package < protected < public; protected is hierarchy, package is locality.
Top pitfall: Returning live collection from getter.
Self-check: Which visibility allows subclass across packages?
Connects to: 12.4, 12.10
Corollaries and General Design Rules Derived from the Axioms
Must-know: Six corollaries restate axioms as: low coupling/lean, single purpose, many small classes, strong mapping, reuse/interfaces, inheritance, standardization, avoid recomputation.
Top pitfall: Treating corollaries as independent checklist ticks.
Self-check: Name two corollaries in one sentence each.
Connects to: 12.8, 12.9
Design Strategies — Strong Domain Mapping, Iterative Refinement, and Standardization
Must-know: Strong mapping enables iterative refinement; standardization (USB/Type-C, auth module, ISO) and patterns give reusable contracts.
Top pitfall: Declaring a standard that nobody adopts.
Self-check: Why does strong mapping make iterative development cheaper?
Connects to: 12.7, 12.9
Design Heuristics and Pitfalls
Must-know: Challenge every class role, split clumsy classes, avoid recomputation/redundancy, distrust messy/too-big/too-small/dislike, especially if not working.
Top pitfall: Assuming small or big alone means good.
Self-check: What derived attribute example would you cache?
Connects to: 12.10, 12.13
Class Diagram Notation — Classes, Attributes, Methods, and Interfaces
Must-know: DCD is mandatory blueprint; class box has name/attributes/operations with visibility + - # ~ and types; Circle example maps to code; interface «interface», component tabs, deployment cuboid.
Top pitfall: Mixing logical package with physical deployment.
Self-check: Draw Circle with radius center and area operation.
Connects to: 12.11, 12.12
Relationships Between Classes — Association, Aggregation, Composition, Generalization, and Dependency
Must-know: Relationships: generalization is-a solid hollow triangle, realization dashed hollow, aggregation open diamond, composition filled diamond, dependency dashed arrow, simple association plain line.
Top pitfall: Adding diamonds to every association.
Self-check: Composition vs aggregation lifetime test?
Connects to: 12.10, 12.12
Multiplicity, Constraints, Components, and Deployment
Must-know: Multiplicity via hold-one-fixed test both directions; constraints {…}, comments folded, components group classes, deployment cuboids show topology.
Top pitfall: Reading multiplicity only one way.
Self-check: One instructor many courses: what multiplicities?
Connects to: 12.11, 12.13
State, Activity, and Dynamic Behavior Diagrams
Must-know: State diagram shows one object's modes with entry/do/exit and transitions event [guard] / action; events: call/signal/time/change; ATM/watch/student/employee traces; fork/join for concurrency.
Top pitfall: State explosion from every field combination.
Self-check: Which event type is after(1 year)?
Connects to: 12.10, 12.14
Process for Building Models and Next Steps
Must-know: Pipeline: brainstorm, sketch, modify/organize, specify, integrate, verify/validate, prototype/test/evaluate; next is 23 GoF patterns (creational/behavioral/structural) then metrics.
Top pitfall: Big-bang modeling before any prototype.
Self-check: What spike would you prototype first?
Connects to: 12.8, 12.9
Was this lecture useful?
BitsNotes AI Assistant
Subject Notes AssistantConfigure AI Chat
Choose how to access the chatbotSigned in as
Powered by BitsNotes — 20 messages per day. No API key needed. Want unlimited access? Use "Bring Your Own Key" mode.
Sign in to use AI Chat
Get 20 free AI messages per day to ask questions about your lecture notes. Sign in with Google or GitHub — it takes 5 seconds.
Sign In to BitsNotesSwitch to "Bring Your Own Key" tab above for unlimited access with any OpenAI-compatible provider.