Design Patterns are an important part of programming efforst. They show patterns, or frameworks, to be followed when writing programs. I have taken examples from the O'Reilly book Head First Design Patterns by Eric and Elisabeth Freeman.
These are the Design Patterns covered in the book:
- Abstract Factory Pattern
- Adapter Pattern
- Command Pattern
- Composite Pattern
- Decorator Pattern
- Facade Pattern
- Factory Pattern
- Iterator Pattern
- Observer Pattern
- Simple Factory
- Singleton Pattern
- State Pattern
- Strategy Pattern
- Template Method Pattern
Object Oriented Principles are also taken from the
Head First Design Patterns book. Here is the list
with some examples.
- Encapsulate what varies
- Favor composition over inheritance
- Program to an interface, not an implementation
- Strive for loosely coupled designs between objects that interact
- Classes should be open for extension, but closed for modification
- Depend on abstractions. Do not depend on concrete classes
- Only talk to your friends
- Don't call us, We'll call you.
- A class should have only one reason to change
Encapsulate what varies - Description:
If you've got some aspect of your code that is changing, say
with every new requirement, then you know you've got a
behavior that needs to be pulled out and separated from all
the stuff that doesn't change. Take the parts that vary
and encapsulate them, so that later you can alter or extend the
parts that vary without affecting those that don't.
Favor composition over inheritance - Example:
Without the Principle:
public class Duck {
public abstract void quack();
public abstract void fly();
public abstract void display();
}
With the Principle:
public class Duck {
private QuackBehavior quackBehavior;
private FlyBehavior flyBehavior;
public void quack() { quackBehavior.quack(); }
public void fly() { flyBehavior.fly(); }
public abstract void display();
}
Program to an interface, not to an implementation -
Example:
Without the Principle:
public ArrayList getList() { return new ArrayList(); }
With the Principle:
public List getList() { return new ArrayList(); }
Strive for loosely coupled designs between objects
that interact - Definition:
Loosely coupled designs allow us to build flexible OO systems
that can handle change because they minimize the interdependency
between objects. The Observer
Pattern provides an object design where subjects and
observers are loosely coupled.
Classes should be open for extension, but closed
for modification - Definition:
The goal is to allow classes to be easily extended to
incorporate new behavior without modifying existing
code. This creates designs that are resilient to
change and flexible enough to take on new functionality
to meet changing requirements. This principle
cannot be applied everywhere! It can be wasteful,
unnecessary, and can lead to complex, hard to understand
code.
Depend on abstractions. Do not depend on
concrete classes
This Principle is also called the "Dependancy Inversion
Principle". It suggests that our high-level
components should not depend on our low-level components,
rather they should both depend on abstractions. The
"inversion" in the name is there because it inverts
the way you typiclly might think about your OO design. You
want low-level components to depend on a higher level
abstraction. Likewise the high-level component is tied to
the same abstraction. Here are some guidelines to help
you avoid OO designs that violate this Principle:
- No variable should hold a reference to a concrete class.
- No class should derive from a concrete class.
- No method should override an implemented method of any of its base classes.
Only talk to your friends - Example:
Without the Principle:
public float getTemp() {
Thermometer thermometer = station.getThermometer();
return thermometer.getTemperature();
}
With the Principle:
public float getTemp() {
return station.getTemperature();
}
Don't call us, we'll call you - Definition:
This principle gives us a way to prevent "dependency rot."
Dependency rot happens when you have high-level components
depending on low-level components depending on sideways
components depending on low-level components, and so on. When
rot sets in, no one can easily understand the way a system is
designed. With the Hollywood principle, we allow low-level
components to hook themselves into a system, but the high-level
components determine when they are needed, and how. In
other words, the high-level components give low-level components
a "don't call us, we'll call you" treatment.
A class should have only one reason to change - Example:
If an aggregate of objects had to also provide the iteration
responsibility, then if we changed the implementation of the
aggregate, then we'd also have to change the iteration portion. This
means the aggregate had two responsibilities, maintaining the aggregate,
and the iteration, or two reasons to change. By separating the
iteration, we give the aggregate only one responsibility, and only one
reason to change.