Design Patterns and Reuse
Reuse
- Most of Object-Oriented design and programming centers around
reuse and reusable code (classes, methods, etc)
- Some types of reuse found in software design:
- integration of off-the-shelf components
- use of standard and custom class libraries
- use of design patterns to solve common problems and protect specific
classes from future change
- use of application frameworks
- With reuse, developers have to decide on buy-vs-build tradeoffs
Components
- Analogy: physical manufacturing
- Most modern product manufacturing is component based
- Some companies specialize in manufacturing components (car parts,
computer parts, etc)
- Some companies specialize in assembling consumer products from
components (auto assembling plants, computer companies)
- Some companies specialize in components to enhance existing products
(car radio/CD/MP3 player, wireless adapter for PCs, etc)
- Component use promotes the idea of somewhat interchangeable parts --
parts that can be used in multiple products, or products that could
choose between multiple types of components
- In software, a component is a self-contained package with well defined
functionality and interface
- Components are mostly "black box"
- This means that the user knows input/output behavior (how to use and
what results to expect), but not the internal details and
workings
- When developing with components, developers can look through component
respositories -- collections of components, often created by independent
developers
- Some components might satisfy a functional requirement as-is, and
others might be close to it -- these could be modified if they are
open-source
- Problems and issues:
- No single standard, and standards not stable
- Requirements must be analyzed to a level that can be matched with
components
- Black box approach leads to quality and trust issues (can't see
what's inside, unless open source)
Application Frameworks
- An application framework is a reusable partial application that
can be specialized (usually through inheritance) to produce custom
applications
- Wikipedia
page on application framework
- Example of a common object-oriented implementation:
- An application framework might consist of a number of classes with
general functionality for a general type of application
- These classes can be extended, such that derived classes will
inherit their general functionality but can also add new
functionality specific to the application domain being developed
- Examples of application frameworks:
- MFC (Microsoft Foundation Classes) for Windows
- WebObjects -- a Java web application server, used in Mac OS X
- One key abstraction: WebObjects provides classes to help manage and
maintain state information in web requests (since basic HTTP is a
stateless request-response protocol)
Design Patterns
- A design pattern is a general solution to a commonly occurring
design problem
- Patterns are much more abstract than components or application
frameworks, which usually focus on specific application domains or
environments
- A design pattern often represents a successful "best practice",
already proven in real world situations
- Originated as an architectural design concept (Christopher Alexander,
1977)
- Gained popularity in computer science with the "Gang of Four" book
- Design Patterns: Elements of Reusable Object-Oriented
Software. Gamma, Helm, Johnson, and Vlissides. 1994.
-
Wikipedia article on Design Patterns
- While there's no single standard format for documenting a design
pattern, one is usually described with at least:
- a name that uniquely identifies the pattern
- context / problem description (what situation it is for, when it
works, etc)
- A solution
- Other factors and details (trade-offs, concerns, constraints,
rationale, known uses, alternatives)
- Design patterns often involve the building of extra classes that
relate somehow to already-specified classes. Frequently, new classes will
relate to old ones through either delegation or
inheritance
Inheritance and Delegation
- Inheritance is, of course, the use of base and derived classes
- The use of inheritance for the sole purpose of reusing code is often
known as implementation inheritance
- Implementation inheritance often does not fit the "is-a" relationship
concept
- Examples: a Set class implemented by inheriting from
HashTable, or a Stack class implemented by
inheriting from LinkedList
- Old Deitel example: Base class Point, derived class
Circle, then derived class Cylinder. Doesn't fit
"is-a" relationship. Definitely implementation inheritance.
- Specification inheritance -- this is the classification of
concepts into type hierarchies. (i.e. the "is-a" relationship)
- Delegation -- a class delegates to another class if it
implements an operation by resending a message to another class
- A wrapper class is a good example of a class that uses
delegation
- Using the "has-a" relationship is one form of delegation -- aggregate
calls upon methods of internal objects to help do tasks
- Delegation is often preferable to implementation
inheritance
- Specification inheritance is better in subtyping situations
- Liskov Substitution Principle -- If an object of type S can be
substituted in all the places where an object of type T is expected, then
S is a subtype of T
- This gives a more formal definition for specification inheritance
- Idea is that if client code uses methods in a superclass, then
developers can add new subclasses without having to change the
client code
Anticipating Change
- In system design, we want a stable architecture to deal with
complexity -- breaking system into subsystems and reducing coupling
- But we also want flexibility for dealing with change later in
development or the life of the system
- Design patterns are often useful in planning solutions for change
(and it's best to try to anticipate change and design for it)
- Common sources of changes:
- New vendor or new technology -- commercial components being
replaced by equivalent ones from a different vendor
- New implementation -- Performance concerns often trigger a
need for more efficient data storage and/or algorithms
- New views -- Testing software with users often uncovers
usability issues, bringing up the need to create additional ways to
view or access the same data
- New complexity of application domain
- Errors -- errors in requirements are discovered when real
users start using the system.
Antipatterns
- Design patterns give constructive advice
- Antipatterns are the opposite of design patterns -- commonly
re-invented bad design examples that should be avoided!
- Some antipatterns:
- The God Object (aka The Blob): A class that knows or
does too much.
- Too much of a program's functionality controlled by
one object, its role becomes god-like
- Makes maintenance more difficult
- Similar in procedural programming to using too many global
variables and/or few subroutines
- The Poltergeist: A short-lived class that has no significant
responsibilities, often stateless and used for trivial tasks. Not
really needed
- Boat Anchor: Unused and possibly obsolete code left in a
system's code base "in case we need it later".
- So named because (metaphorically) only valuable use is to throw
overboard and use as boat mooring
- Makes maintaining code more difficult. Programmers reading code
could waste time looking at irrelevant and unused code, trying to
figure out how it relates
- More
Anti-patterns