Transcript CS 441: Principles of Software Design
CS 4240: The OO Paradigm Revisited
Readings: Chap. 1 of
Design Patterns Explained
OO (some review)
Coupling, cohesion
Old problems
Before OO, functional decomposition Break problem down Function deals with subproblem Hierarchical. Levels of abstraction Problems: Control and coordination centered in main method Required changes have big impacts Logic may be distributed Data changes affect may modules
Functions:
What we call them: functions, methods, modules Functions are a core construct in OO and non-OO programs Principals of good functions apply in either language But less of a problem in OO – can you think why?
What makes a function good?
Your answers:
Good qualities in functions:
Lots written about this!
Clean Code: A Handbook of Agile SW Craftsmanship
Robert C. Martin Read Chapter 3 in UVa digital library version
Good Qualities in Functions
Small How small?
Do One Thing: Strong Cohesion Why?
One level of abstraction per function Thus, functions fall into levels of abstraction Name reflects the one task it does
Interface Qualities of Functions
What about its interface?
Inputs, return value/arguments Other sources of data or “output” Side effects Some rules?
Good Qualities in Functions (2)
Number of arguments: small “Bundling” arguments Flag arguments What are they? What bad thing do they suggest is happening?
Avoid side effects Avoid output arguments
Good Qualities in Functions (3)
Don’t Repeat Yourself (DRY) Command/Query Separation Do something. Or answer something.
Don’t do both.
Returning Errors Return value? Output argument?
Burden on caller?
Exceptions: what advantages?
Design Representation
If you’re just programming with functions (not OO), how could you represent your system?
Example: Structure Chart
Comments on Struct. Chart
How are data and functions tied together?
Can procedural abstraction be done?
Data abstraction?
How sensitive to change are parts of this design? Where?
Page 8 of
DPE
text: can a function cope with variability in data? (Will this be an issue?)
Back to Shalloway and Trott…
Requirements
See textbook’s discussion on requirements and why they change.
Bottom line:
Change is inevitable. Deal with it.
Design Principles (again)
Decomposition leads to modularity Properties of modules: Internal “goodness” Inter-module relationships Cohesion Coupling Note: old terms first defined for function oriented modules
Cohesion of a module
“How closely operations [what’s encapsulated] in a module are related.” Think of: Strength of purpose A cohesive group of people works well together towards a goal Extreme of non-cohesive OO module: a
god class
Coupling between modules
“strength [or goodness] of the connection between two modules.” We want quality connections. Why?
Flexibility, independence of modules “Looser” connections, less brittle system Reusability Goal: Loosely-coupled modules, each highly cohesive
Coupling: What’s “Good”?
How do modules “connect”?
Invoke operations in each other [dynamic] Small operations, or start/invoke something larger Pass data to each other [dynamic] Defined in terms of each other [static] General: Simple, as little as possible (data) Direct connections, very visible Flexible E.g. report an event, but not tell the other module how to handle it
Back to Functional Decomposition
Side effects Finding bugs is the problem, not fixing them Change to data impact many functions Snowball effect, cascade of changes
OO Improves This Because
Modules become responsible for: Encapsulating data Controlling access, maintaining intergrity Encapsulating operations on data Functionality is bound to data Why is this an example of DRY principle?
For a modules in OO, we define: Responsibilities, data, operations
Classes in Java, C++
“My responsibilities?” What my role is!
Clear how data and operations are defined when we write a Java class, but what about responsibilities?
Implied by operations?
Answer: Note in the code. Maybe in the comments. Certainly in the design (even if implicit) Responsibilities matter a lot in understanding the design.
Step back: Perspectives of modules
Martin Fowler (UML Distilled) talks about three levels of perspectives to talk about modules (or SW development) Note we’re practicing abstraction in doing this!
Explain why to me later on!
Note: it’s easier to understand this if you think about limiting it to objects for now
Levels of perspective in OO
Conceptual Domain-level, problem-level -- not yet considering solutions What is an object’s responsibilities?
Specification Solution-level, but an abstract view Interfaces, not internal implementation Implementation Code level: full details of how it’s coded
So… What’s an Object?
Depends on what level you’re using, where you’re at in development Conceptual: set of responsibilities Specification: set of methods (an interface) that meets its responsibilities Implementation: coding you’ve learned to do Designers work at Specification level (mostly) Analysts work at Conceptual level (mostly)
Classes, Objects and Instantiation
Review!
What’s an instance? What’s instantiation?
Do we need classes to do OO programming?
No. But why are they helpful?
Define common properties. (DRY again.)
Abstract Types
Review: abstract class vs. interface How are they used? What’s common about them?
Explain: Collections of these. References to these.
Review: polymorphism
What are the mechanics of polymorphism in OO? (Implementation level perspective) At a higher level, what’s it for?
More (not from text)
More on coupling, cohesion
Cohesion
How diverse are the things inside an “entity”
A what? Module, function,… In OO a class.
What’s this mean?
Class should represent a single abstraction
Or, it should address a single general responsibility
Problems Created by Bad Cohesion
Hard to understand the class If two abstractions grouped into one class, that implies a one-to-one relationship
What if this changes?
Often we specialize a class along a dimension
This new thing is like the existing one except we extend it in one area (dimension)
Problems arise when each of the several abstractions need such specialization
Note meaning of “specialization” here
The “Multiplicity” Problem
Consider an Account class that holds:
Customer name, address, tax ID, Account status, etc.
What if one customer needs two accounts?
Two Account objects, but each stores name and address What if one account has two owners?
You can’t do this, unless you create a collection in each Account to hold owner info
Specializing along Dimensions
Let’s say we need variations on class Account
First, based on account type: Cash Account, Credit Account Second, based on customer type: Individual Account, Institutional Account These are two dimensions, but are they mutually exclusive?
We often compose along two dimensions E.g. Individual Cash Account, Individual Credit Account, etc.
Specialization often implemented as inheritance: Do we really want multiple inheritance?
Inheritance Diamonds
Structures like this cause messy problems!
Account Cash Account Credit Account Individual Account Instiutional Account Individual Cash Account Individual Credit Account
Two more classes here
Separating Abstractions
Composition across dimensions achieved by aggregation (“PART-OF”)
You can see how this improves earlier problem too
owner
Account Customer
* 1..*
Cash Account Credit Account Individual Customer Instiutional Customer
An OO Design Principle…
Prefer aggregation over inheritance!
Keep in mind: Often at the conceptual perspective, the “IS-A” relationship is true But at the design/implementation level, we don’t use inheritance
How to Achieve Better Cohesion
Some of this is just good OO experience We can learn from database normalization
Eliminate redundancy Attributes should have a single value and should not have structure (repeating groups of things) Attributes always describe an instance of its containing class
That’s what attributes are all about! State values that define a particular instance Note: there are always tradeoffs! Sometimes we combine abstractions into one class for efficiency.
Coupling and Class Design
How dependent an object/class is on the world around it
How many connections
Nature of the connections Will changes cause a “ripple effect”?
Our goals:
Reduce coupling if possible
Improve nature of necessary coupling
Forms of Coupling (from Richter)
Identity Coupling
An object contains a reference or pointer to another object
Eliminate associations or make them one way Representational Coupling
An object refers to another through that object’s interface
How it does this affects the degree of coupling
Forms of Coupling (cont’d)
Subclass Coupling
Object refers to another object using a subclass reference for that object
Not the more general superclass or interface
A client should refer to the most general type possible
Why? Subclasses may be added later, possibly by someone else Try to write code that minimizes dependencies on subclass details
Instead rely on the common interface defined in the superclass or interface
Reminder: Use Java Interfaces to Avoid Subclass Coupling
Java’s interfaces; C++ classes with pure virtual functions and no data members Interfaces define a role not a class abstraction
Many classes can pay that role
THE POINT:
We can define reference to a thing in terms of the role (interface) instead of the class type
Forms of Coupling (cont’d)
Inheritance coupling
A subclass is coupled to its superclass at compile-time
In general, prefer late to early Seems like the only way to do things, but ask: While the program executes, does an object need to change its subclass?
Aggregation is supported at run-time
We’ll see the State design pattern later
Shy Code and the Law of Demeter
See handout on the Law of Demeter Summary: An object’s method should only call other methods that belong to: Itself (the current object) Any parameter object that was passed to it An object it created Any of its components objects What does this rule out? (Ponder that.) Delegation