Purpose

advertisement
Design Pattern
SSE USTC
Qing Ding
Factory Method
In injection molding,
manufacturers process
plastic molding powder
and inject the plastic into
molds of desired shapes.
Like the Factory
Method, the subclasses
(in this case the molds)
determine which classes
to instantiate. In the
example, the
ToyHorseMold class is
being instantiated.
Factory

Purpose
–

Participant Correspondence:
–

defines an interface for creating objects, but lets subclasses
decide which classes to instantiate.
The Injection Mold corresponds to the Product, as it defines the
interface of the objects created by the factory. A specific mold
(ToyHorseMold or ToyCarMold) corresponds to the
ConcreteProduct, as these implement the Product interface. The
toy company corresponds to the Creator, since it may use the
factory to create product objects. The division of the toy company
that manufactures a specific type of toy (horse or car) corresponds
to the ConcreteCreator.
Consequences:
–
Creating objects with an Injection Mold is much more flexible than
using equipment that only created toy horses. If toy unicorns
become more popular than toy horses, the Injection Mold can be
extended to make unicorns.
Factory Method
A Bread Machine
allows its user to
make bread. The
recipe used
determines the
type of bread to be
made.
Factory

Purpose
–

Participant Correspondence:
–

defines an interface for creating objects, but lets subclasses
decide which classes to instantiate.
The Bread Machine corresponds to the Product, as it
defines the interface of the objects created by the factory. A
specific recipe (BasicBreadRecipe or CheeseBreadRecipe)
corresponds to the ConcreteProduct, as these implement
the Product interface. The user corresponds to the Creator,
since he or she uses the factory to create product objects.
Consequences:
–
Creating objects with a bread machine is much more
flexible than using baking equipment that only created one
type of bread.
Simple Factory Code
//抽象产品角色
public interface Car{
public void drive();
}
//具体产品角色
public class Benz implements Car{
public void drive() {
System.out.println("Driving Benz ");
}
}
public class Bmw implements Car{
public void drive() {
System.out.println("Driving Bmw ");
}
}
//工厂类角色
public class Driver{
//工厂方法.注意 返回类型为抽象产品角色
public static Car driverCar(String s)throws Exception {
//判断逻辑,返回具体的产品角色给Client
if(s.equalsIgnoreCase("Benz"))
return new Benz();
else if(s.equalsIgnoreCase("Bmw"))
return new Bmw();
......
else throw new Exception();
//欢迎暴发户出场......
public class Magnate{
public static void main(String[] args){
try{
//告诉司机我今天坐奔驰
Car car = Driver.driverCar("benz");
//下命令:开车
car.drive();
。。。
Factory Method Code
//抽象产品角色,具体产品角色与简单工厂模式类似,只是变得复杂了些,
这里略。
//抽象工厂角色
public interface Driver{
public Car driverCar();
}
public class BenzDriver implements Driver{
public Car driverCar(){
return new Benz();
}
}
public class BmwDriver implements Driver{
public Car driverCar() {
return new Bmw();
}
}
//应该和具体产品形成对应关系...
//有请暴发户先生
public class Magnate {
public static void main(String[] args) {
try{
Driver driver = new BenzDriver();
Car car = driver.driverCar();
car.drive();
}
……
}
Abstract Factory
Sheet metal stamping
equipment is an example
of an Abstract Factory
for creating auto body
parts. Using rollers to
change the dies, the
concrete class can be
changed. The possible
concrete classes are
hoods, trunks, roofs, left
and right front fenders,
etc. The master parts list
ensures that classes will
be compatible. Note that
an Abstract Factory is a
collection of Factory
Methods.
Abstract Factory

Purpose
–

Participant Correspondence:
–

To provide an interface for creating families of related
objects without specifying concrete classes.
The Master Parts List corresponds to the client, which
groups the parts into a family of parts. The Stamping
Equipment corresponds to the Abstract Factory, as it is an
interface for operations that create abstract product objects.
The dies correspond to the Concrete Factory, as they create
a concrete product. Each part category (Hood, Door, etc.)
corresponds to the abstract product. Specific parts (i.e.,
driver side door for 1998 Nihonsei Sedan) corresponds to
the concrete products.
Consequences:
–
Concrete classes are isolated in the dies. Changing dies to
make new product families (Hoods to Doors) is easy.
Builder
Fast food restaurants use
a Builder to construct
their children’s meals.
There can be variation in
the contents (the main
course, the drink, or the
toy), but the process for
building a children’s
meal remains the same.
Note that the Builder
returns a finished
product, whereas the
Abstract Factory returns
a collection of related
parts.
Builder

Purpose
–

Participant Correspondence:
–

separates the construction of a complex object from its
representation, so the same construction process can create
different representations.
The Kid’s Meal concept corresponds to the builder, which is an
abstract interface for creating parts of the Product object. The
restaurant crew corresponds to the ConcreteBuilder, as they will
assemble the parts of the meal (i.e. make a hamburger). The
cashier corresponds to the Director, as he or she will specify the
parts needed for the Kid’s Meal, resulting in a complete Kid’s meal.
The Kid’s Meal package corresponds to the Product, as it is a
complex object created via the Builder interface.
Consequences:
–
The internal representation of the Kid’s meal can vary. The
construction process is isolated from the representation. The same
process is used by virtually all of the fast food chains. There is
finer control over the construction process and the internal
structure of the finished product. Hence two Kid’s Meals from the
same restaurant can consist of entirely different items.
Builder Code
//不同的媒体形式:
class Media extends ArrayList {}
class Book extends Media {}
class Magazine extends Media {}
class WebSite extends Media {}
// 进而包含不同的媒体组成元素:
class MediaItem {
private String s;
public MediaItem(String s) { this.s = s; }
public String toString() { return s; }
}
Builder Code
class Chapter extends MediaItem {
public Chapter(String s) { super(s); }
}
class Article extends MediaItem {
public Article(String s) { super(s); }
}
class WebItem extends MediaItem {
public WebItem(String s) { super(s); }
}
// 抽象建造者角色,它规范了所有媒体建造的步骤:
class MediaBuilder {
public void buildBase() {}
public void addMediaItem(MediaItem item) {}
public Media getFinishedMedia() { return null; }
}
//具体建造者角色
class BookBuilder extends MediaBuilder {
private Book b;
public void buildBase() {
System.out.println("Building book framework");
b = new Book();
}
public void addMediaItem(MediaItem chapter) {
System.out.println("Adding chapter " + chapter);
b.add(chapter);
}
public Media getFinishedMedia() { return b; }
}
class MagazineBuilder extends MediaBuilder {
private Magazine m;
public void buildBase() {
System.out.println("Building magazine framework");
m = new Magazine();
}
public void addMediaItem(MediaItem article) {
System.out.println("Adding article " + article);
m.add(article);
}
public Media getFinishedMedia() { return m; }
}
class WebSiteBuilder extends MediaBuilder {
private WebSite w;
public void buildBase() {
System.out.println("Building web site framework");
w = new WebSite();
}
public void addMediaItem(MediaItem webItem) {
System.out.println("Adding web item " + webItem);
w.add(webItem);
}
public Media getFinishedMedia() { return w; }
}
//指导者角色,也叫上下文
class MediaDirector {
private MediaBuilder mb;
public MediaDirector(MediaBuilder mb) {
this.mb = mb; //具有策略模式相似特征的
}
public Media produceMedia(List input) {
mb.buildBase();
for(Iterator it = input.iterator(); it.hasNext();)
mb.addMediaItem((MediaItem)it.next());
return mb.getFinishedMedia();
}
}
//测试程序——客户程序角色
public class BuildMedia extends TestCase {
private List input = Arrays.asList(new MediaItem[] {
new MediaItem("item1"), new MediaItem("item2"),
new MediaItem("item3"), new MediaItem("item4"), });
public void testBook() {
MediaDirector buildBook = new MediaDirector(new BookBuilder());
Media book = buildBook.produceMedia(input);
String result = "book: " + book;
System.out.println(result);
assertEquals(result, "book: [item1, item2, item3, item4]");
}
public void testMagazine() {
MediaDirector buildMagazine = new MediaDirector(new MagazineBuilder());
Media magazine = buildMagazine.produceMedia(input);
String result = "magazine: " + magazine;
System.out.println(result);
assertEquals(result, "magazine: [item1, item2, item3, item4]");
}
public void testWebSite() {
MediaDirector buildWebSite = new MediaDirector(new WebSiteBuilder());
Media webSite = buildWebSite.produceMedia(input);
String result = "web site: " + webSite;
System.out.println(result);
assertEquals(result, "web site: [item1, item2, item3, item4]");
}
public static void main(String[] args) {
junit.textui.TestRunner.run(BuildMedia.class);
}
}
Prototype
The mitotic division of a
cell results in two cells
of identical genotype.
This cell “cloning” is an
example of the
Prototype pattern in that
the original cell takes an
active role in creating a
new instance of itself.
Prototype

Purpose
–

Participant Correspondence:
–

specifies the kind of objects to instantiate using a
prototypical instance.
The cell corresponds to the Prototype, as it has an
“interface” for cloning itself. A specific instance of a cell
corresponds to the ConcretePrototype. The DNA or genetic
blue print corresponds to the Client, as it creates a new cell
by instructing a cell to divide and clone itself.
Consequences:
–
Many applications build objects from parts and subparts.
For convenience, complex systems can be instantiated
using subparts again and again. In complex organisms,
cells divide, and form various organs which in turn, make up
the organism.
Prototype Code
class PrototypeManager {
private static PrototypeManager pm;
private Map prototypes=null;
private PrototypeManager() {
prototypes=new HashMap();
}
//使用单例模式来得到原型管理器的唯一实例
public static PrototypeManager getManager() {
if(pm==null) {
pm=new PrototypeManager();
}
return pm;
}
public void register(String name , Object prototype) {
prototypes.put(name , prototype);
}
public void unregister(String name) {
prototypes.remove(name);
}
public Prototype getPrototype(String name) {
if(prototypes.containsKey(name)) {
//将清单中对应原型的复制品返回给客户
return (Prototype) ((Prototype)prototypes.get(name)).clone();
}else {
Prototype object=null;
try {
object =(Prototype)Class.forName(name).newInstance();
register(name , object);
} catch(Exception e) {
System.err.println("Class "+name+"没有定义!");
}
return object;
。。。
Singleton
The office of the
Presidency of the United
States is an example of a
Singleton, since there
can be at most one active
president at any given
time. Regardless of who
holds the office, the title
“The President of the
United States” is a
global point of reference
to the individual.
Singleton

Purpose
–

Participant Correspondence:
–

ensures that a class has only one instance, and provides a
global point of reference to that instance.
The Office of the Presidency of the United States
corresponds to the Singleton. The office has an instance
operator (the title of “President of the United States”) which
provides access to the person in the office. At any time, at
most one unique instance of the president exists.
Consequences:
–
The title of the office provides controlled access to a sole
instance of the president. Since the office of the presidency
encapsulates the president, there is strict control over how
and when the president can be accessed.
饿汉式
public class Singleton {
//在自己内部定义自己一个实例
//注意这是private 只供内部调用
private static Singleton instance = new Singleton();
//如上面所述,将构造函数设置为私有
private Singleton(){
}
//静态工厂方法,提供了一个供外部访问得到对象的静态方法
public static Singleton getInstance() {
return instance;
}
}
懒汉式
public class Singleton {
//和上面有什么不同?
private static Singleton instance = null;
//设置为私有的构造函数
private Singleton(){
}
//静态工厂方法
public static synchronized Singleton getInstance() {
//这个方法比上面有所改进
if (instance==null)
instance=new Singleton();
return instance;
}
}
public class Singleton {
//用来存放对应关系
private static HashMap sinRegistry = new HashMap();
static private Singleton s = new Singleton();
//受保护的构造函数
protected Singleton() {}
public static Singleton getInstance(String name) {
if(name == null)
name = "Singleton";
if(sinRegistry.get(name)==null) {
try{
sinRegistry.put(name , Class.forName(name).newInstance());
}catch(Exception e) {
e.printStackTrace();
}
}
return (Singleton)(sinRegistry.get(name));
}
public void test() {
System.out.println("getclasssuccess!");
}
}
public class SingletonChild1 extends Singleton {
public SingletonChild1(){}
static public SingletonChild1 getInstance() {
return (SingletonChild1)Singleton.getInstance("SingletonChild1");
}
public void test() {
System.out.println("getclasssuccess111!");
}
}
Adapter
A 1/2" drive ratchet will
not ordinarily work with
a 1/4" drive socket.
Using an Adapter, the
female end interfaces
with the 1/2" drive
ratchet, and the male end
interfaces with the 1/4"
socket.
Adapter

Purpose
–

Participant Correspondence:
–

allows otherwise incompatible classes to work together by
converting the interface of one class to an interface
expected by the clients.
The ratchet corresponds to the Target, as it is the domain
specific interface that the client uses. The socket
corresponds to the Adaptee, since it contains an interface
(1/4” drive) that needs adapting. The socket adapter
corresponds to the Adapter, as it adapts the inteface of the
Adaptee to that of the Target.
Consequences:
–
The Adaptee is adapted to the target by committing to a
concrete adapter object.
Adapter Code
class Circle extends Shape {
//这里引用了TextCircle
private TextCircle tc;
public Circle () {
tc= new TextCircle(); //初始化
}
void public display() {
//在规定的方法里面调用TextCircle原来的方法
tc.displayIt();
}
}
Bridge
A switch is a device for
turning lights, ceiling
fans, garbage disposals
on or off. The actual
implementation of the
switch is decoupled from
the abstract switch. This
decoupling of the
abstraction and
implementation is an
example of the Bridge
Pattern.
Bridge

Purpose
–

Participant Correspondence:
–

decouples an abstraction from its implementation, so that the two
can vary independently. Note that the schematics of house wiring
state only where switches will be located, not what type of switch it
will be.
In the example, the Switch corresponds to the Abstraction. The
SwitchImp corresponds to the Implementor. The specific type of
switch would correspond to the ConcreteImplementor.
Consequences:
–
The interface and implementation are decoupled. With the Bridge
the implementation of an abstraction is often done at run time. In
the switch example, the selection of a physical switch can be
delayed until the switch is actually wired. The switch can be
changed without requiring a redesign of the house. Implementation
details are hidden. Builders need only know that a switch is
needed. The house can be framed, wired, and dry walled without
anyone knowing the concrete implementation of the switch.
Bridge
A magician relies on the
bridge pattern for his act.
The act is developed
with a volunteer, but the
identity of the volunteer
is not known until the
time of the performance
Bridge

Purpose
–

Participant Correspondence:
–

decouples an abstraction from its implementation, so that the two
can vary independently. Note that a magician’s act requires an
abstract volunteer. The specific identity of the volunteer is not
known until the time of the act. The specific identity can (and often
does) vary from performance to performance.
In the example, the Volunteer corresponds to the Abstraction. The
ChosenVolunteer corresponds to the Implementor. The specific
volunteer (Jane Smith) corresponds to the ConcreteImplementor.
Consequences:
–
The interface and implementation are decoupled. With the Bridge
the implementation of an abstraction is often done at run time. In
the magician example, the selection of a specific volunteer can be
delayed until the performance. The volunteer can be changed
without requiring a redesign of the act. Implementation details are
hidden. The magician does not need to know who is in the
audience before hand.
Bridge Code (AWT)
//抽象部分(前端)的抽象角色
class Abstraction {
//维护着一个指向实现(Implementor)角色的引用
private Implementation implementation;
public Abstraction(Implementation imp) {
implementation = imp;
}
// 下面定义了前端(抽象部分)应该有的接口
public void service1() {
//使用了后端(实现部分)已有的接口
//组合实现功能
implementation.facility1();
implementation.facility2();
}
public void service2() {
implementation.facility2();
implementation.facility3();
}
public void service3() {
implementation.facility1();
implementation.facility2();
implementation.facility4();
}
// for use by subclasses:
protected Implementation getImplementation() {
return implementation;
}
}
//抽象部分(前端)的精确抽象角色
class ClientService1 extends Abstraction {
public ClientService1(Implementation imp) { super(imp); }
//使用抽象角色提供的方法组合起来完成某项功能
//这就是为什么叫精确抽象角色(修正抽象角色)
public void serviceA() {
service1();
service2();
}
public void serviceB() {
service3();
}
}
//另一个精确抽象角色,和上面一样的省略
class ClientService2 extends Abstraction {
。。。。
//这里是直接通过实现部分的方法来实现一定的功能
public void serviceE() {
getImplementation().facility3();
}
}
//实现部分(后端)的实现角色
interface Implementation {
//这个接口只是定义了一定的接口
void facility1();
void facility2();
void facility3();
void facility4();
}
//具体实现角色就是要将实现角色提供的接口实现
//并完成一定的功能
//这里省略了
class Implementation1 implements Implementation {
。。。
Composite
Arithmetic expressions
can be expressed as trees
where an operand can be
a number or an
arithmetic expression.
Since the individual
objects, and
compositions of
individual objects are
treated uniformly, an
arithmetic expression is
an example of the
Composite pattern.
Composite

Purpose
–

Participant Correspondence:
–

composes objects into tree structures, and lets clients treat
individual objects and compositions uniformly.
Any arithmetic expression is a component. Numeric
operands correspond to leafs, while expressions containing
at least one operator correspond to composites. Whoever
forms the expression is the client.
Consequences:
–
The composite pattern defines class hierarchies consisting
of leaf objects and composite objects. Composite objects
are treated the same way as leaf objects (their value is
added, subtracted, etc. from another value). With
composites, it is easy to add new kinds of components. For
example, the following expression can be rewritten:
Composite
Composite is often exhibited in
recipes. A recipe consists of a
list of ingredients which may be
atomic elements (such as milk
and parsley) or composite
elements (such as a roux)
Composite

Purpose
–

Participant Correspondence:
–

composes objects into tree structures, and lets clients treat
individual objects and compositions uniformly.
Any item in a recipe is a component. The simple elements such as
milk, correspond to the leaf objects. Elements such as the white
roux, which are themselves composed of leaf elements are
composites. The chef corresponds to the client.
Consequences:
–
Recipes can be written more simply by combining primitive and
composite objects. When combining elements of a recipe,
composite elements are added the same way that simple elements
are. It is easy to add new kinds of elements, as is evidenced by
the frequency in which recipes are combined.
Composite Code (JUnit)
//Test接口——抽象构件角色
public interface Test {
/**
* Counts the number of test cases that will be run by this test.
*/
public abstract int countTestCases();
/**
* Runs a test and collects its result in a TestResult instance.
*/
public abstract void run(TestResult result);
}
//TestSuite类的部分有关源码——Composite角色,它实现了接口Test
public class TestSuite implements Test {
//用了较老的Vector来保存添加的test
private Vector fTests= new Vector(10);
private String fName;
……
/**
* Adds a test to the suite.
*/
public void addTest(Test test) {
//注意这里的参数是Test类型的。这就意味着TestCase和TestSuite以及以后
//实现Test接口的任何类都可以被添加进来
fTests.addElement(test);
}
……
/**
* Counts the number of test cases that will be run by this test.
*/
public int countTestCases() {
int count= 0;
for (Enumeration e= tests(); e.hasMoreElements(); ) {
Test test= (Test)e.nextElement();
count= count + test.countTestCases();
}
return count;
}
/**
* Runs the tests and collects their result in a TestResult.
*/
public void run(TestResult result) {
for (Enumeration e= tests(); e.hasMoreElements(); ) {
if (result.shouldStop() )
break;
Test test= (Test)e.nextElement();
//关键在这个方法上面
runTest(test, result);
}
}
//这个方法里面就是递归的调用了,至于你的Test到底是什么类型的
//只有在运行的时候得知
public void runTest(Test test, TestResult result) {
test.run(result);
}
……
}
//TestCase的部分有关源码——Leaf角色,你编写的测试类就是继承自它
public abstract class TestCase extends Assert implements Test {
……
/**
* Counts the number of test cases executed by run(TestResult result).
*/
public int countTestCases() {
return 1;
}
/**
* Runs the test case and collects the results in TestResult.
*/
public void run(TestResult result) {
result.run(this);
}
……
}
Decorator
Paintings can be hung on
a wall with or without
frames. Often, paintings
will be matted and
framed before hanging.
The painting, frame, and
matting form a visual
component
Decorator

Purpose
–

Participant Correspondence:
–

attaches additional responsibilities to an object dynamically.
The abstract “painting” corresponds to the Component. A
concrete painting corresponds to the ConcreteComponent.
The frame and matte correspond to the Decorator.
Consequences:
–
Adding or removing frames and mattes provide more
flexibility than requiring all paintings to have the same frame.
Paintings can be customized with the addition of mattes and
frames. The cost of customization is determined by the
framing and matting options chosen. The decorator and
component remain separate.
Decorator
The graphics displays used
on GUI desktops use decorators
such as toolbars, status bars,
and scroll bars.
Decorator

Purpose
–

Participant Correspondence:
–

attaches additional responsibilities to an object dynamically.
The windowcorresponds to the Component. A specific
window corresponds to the ConcreteComponent. The
borders, status bars, and scroll bars correspond to the
Decorator.
Consequences:
–
Adding items such as scroll bars as needed provides more
flexibility than requiring all windows to have scroll bars. If
scrolling is not needed, the cost of a scroll bar is not
incurred. The decorator and component remain separate.
Decorator Code (JUnit)
//这个就是抽象构件角色
public interface Test {
/**
* Counts the number of test cases that will be run by this test.
*/
public abstract int countTestCases();
/**
* Runs a test and collects its result in a TestResult instance.
*/
public abstract void run(TestResult result);
}
//具体构件对象,但是这里是个抽象类
public abstract class TestCase extends Assert implements Test {
……
public int countTestCases() {
return 1;
}
……
public TestResult run() {
TestResult result= createResult();
run(result);
return result;
}
public void run(TestResult result) {
result.run(this);
}
……
}
//装饰角色
public class TestDecorator extends Assert implements Test {
//这里按照上面的要求,保留了一个对构件对象的实例
protected Test fTest;
public TestDecorator(Test test) {
fTest= test;
}
/**
* The basic run behaviour.
*/
public void basicRun(TestResult result) {
fTest.run(result);
}
public int countTestCases() {
return fTest.countTestCases();
}
public void run(TestResult result) {
basicRun(result);
}
public String toString() {
return fTest.toString();
}
public Test getTest() {
return fTest;
}
}
//具体装饰角色,这个类的增强作用就是可以设置测试类的执行次数
public class RepeatedTest extends TestDecorator {
private int fTimesRepeat;
public RepeatedTest(Test test, int repeat) {
super(test);
if (repeat < 0)
throw new IllegalArgumentException("Repetition count must be > 0");
fTimesRepeat= repeat;
}
//看看怎么装饰的吧
public int countTestCases() {
return super.countTestCases()*fTimesRepeat;
}
public void run(TestResult result) {
for (int i= 0; i < fTimesRepeat; i++) {
if (result.shouldStop())
break;
super.run(result);
}
}
public String toString() {
return super.toString()+"(repeated)";
}
}
使用的时候,就可以采用下面的方式:
TestDecorator test = new RepeatedTest(new TestXXX() , 3);
Facade
When ordering from a
catalog, consumers do
not have direct contact
with the Order
Fulfillment, Billing, and
Shipping departments.
The Customer Service
Representative acts as a
Facade, or unified
interface, to each of the
departments involved in
the transaction.
Facade

Purpose
–

Participant Correspondence:
–

The customer service representative corresponds to the Façade. The
individual departments correspond to the subsystem classes.
Consequences:
–

defines a unified, higher level interface to a subsystem, that makes it
easier to use.
Clients are shielded from individual departments. When ordering an item, it
is not necessary to check the stock, generate an invoice, and arrange for
shipping. All steps are accomplished through the customer service
representative. The internal structure of the organization can be changed
without affecting the client. For example, the shipping department can be
contracted to another organization, without impacting the client’s interface
with the company.
Note:
–
Some catalog department stores require the customer to select the item,
check to see if it is in stock, order it, go to a counter to pay for it, and then
go to another counter to receive it. In this example, a façade is not used.
Facade
The headquarters of an ambulance
service consists of several devices for
different purposes, for instance
ambulances with different levels of
equipment and differently skilled
crews, pediatric ambulances,
helicopters, and so on. On the other
hand easy use of this system – i.e..
calling for help – is essential.
Facade

Purpose
–

Participant Correspondence:
–

defines a unified, higher level interface to a subsystem, that makes
it easier to use.
The emergency services operator (9-1-1 operator in North America)
corresponds to the Façade. The individual emergency services
correspond to the subsystem classes.
Consequences:
–
Clients are shielded from individual departments. When
emergency services are needed, it is not necessary to call the
ambulance, police and fire departments separately. The
emergency services operator dispatches services as needed.
There is a weak coupling between services. In the event of a
burglary, the fire brigade need not be dispatched. Regardless of
who is dispatched, the client interface remains the same.

Facade模式的一个典型应用就是进行数据库
连接。一般我们在每一次对数据库进行访
问,都要进行以下操作:先得到connect实例,
然后打开connect获得连接,得到一个
statement,执行sql语句进行查询,得到查询
结果集。
我们可以将这些步骤提取出来,封装在一个类
里面。这样,每次执行数据库访问只需要
将必要的参数传递到这个类中就可以了。
Flyweight
Most telephone
subscribers are unaware
that the pool of Tone
generators (such as dial
tone, busy tone or
reorder tone) is much
smaller than the number
of subscribers. The pool
of Dial Tone generators
is an example of a
Flyweight.
Flyweight

Purpose
–

Participant Correspondence:
–

uses sharing to support large numbers of objects efficiently.
Tone generators correspond to the Flyweight. The physical Dial
Tone generator corresponds to the ConcreteFlyweight. The Tone
Generator pool corresponds to the FlyweightFactory. When a tone
generator is requested, it is connected to the subscriber line.
When it is no longer need, it is disconnected so that it can be used
by another. The telephone switch corresponds to the client, since it
maintains the reference to the flyweights.
Consequences:
–
Developing mechanisms for sharing items between multiple users
is not without cost. The cost is offset by a reduction in the number
of tone generators required, and the reduction in space required in
the physical plant.
Flyweight Code
//这便是使用了静态属性来达到共享
//它使用了数组来存放不同客户对象要求的属性值
//它相当于享元角色(抽象角色被省略了)
class ExternalizedData {
static final int size = 5000000;
static int[] id = new int[size];
static int[] i = new int[size];
static float[] f = new float[size];
static {
for(int i = 0; i < size; i++)
id[i] = i;
}
}
//这个类仅仅是为了给ExternalizedData的静态属性赋值、取值
//这个充当享元工厂角色
class FlyPoint {
private FlyPoint() {}
public static int getI(int obnum) {
return ExternalizedData.i[obnum];
}
public static void setI(int obnum, int i) {
ExternalizedData.i[obnum] = i;
}
public static float getF(int obnum) {
return ExternalizedData.f[obnum];
}
public static void setF(int obnum, float f) {
ExternalizedData.f[obnum] = f;
}
public static String str(int obnum) {
return "id: " +
ExternalizedData.id[obnum] + ", i = " +
ExternalizedData.i[obnum] + ", f = " + ExternalizedData.f[obnum];
}
}
//客户程序
public class FlyWeightObjects {
public static void main(String[] args) {
for(int i = 0; i < ExternalizedData.size; i++) {
FlyPoint.setI(i, FlyPoint.getI(i) + 1);
FlyPoint.setF(i, 47.0f);
}
System.out.println( FlyPoint.str(ExternalizedData.size -1));
}
}
Proxy
An 800 (8xx) number is
a proxy for the real
directory number.
Callers will dial the 800
number, just as they
would dial the actual
directory number.
Proxy

Purpose
–

Participant Correspondence:
–

provides a surrogate or place holder to provide access to an
object.
The 800 number corresponds to the Proxy. The 800 number
is not actually assigned to a line, but it is translated to a
number that is. The directory number corresponds to the
real subject. It is assigned to a line. The business
corresponds to the subject. It is the interface that allows the
RealSubject and Proxy to work together.
Consequences:
–
The proxy introduces a level of indirection when accessing
an object. The indirection can be used for security, or
disguising the fact that an object is located in a different
address space. In the case of the 800 number, it is a remote
proxy, which hides the actual location of the business.
Proxy Code (论坛发帖权限的控制)
public interface MyForum
{
public void AddFile();
}
public class MyForumProxy implements MyForum {
private RealMyForum forum = new RealMyForum() ;
private int permission ; //权限值
public MyForumProxy(int permission) {
this.permission = permission ;
}
//实现的接口
public void AddFile() {
//满足权限设置的时候才能够执行操作
//Constants是一个常量类
if(Constants.ASSOCIATOR == permission)
forum.AddFile();
else
System.out.println("You are not a associator of MyForum ,please
registe!");
}
}
Chain of Responsibility
A mechanical sorting
bank uses a single slot
for all coins. As each
coin is dropped, a Chain
of Responsibility
determines which tube
accommodates each
coin. If a tube cannot
accommodate the coin,
the coin is passed on
until a tube can accept
the coin.
Chain of Responsibility

Purpose
–

Participant Correspondence:
–

avoids coupling the sender of a request to the receiver.
The person dropping a coin in the bank corresponds to the
client, since he is initiating the request. The coin
corresponds to the request. Each tube corresponds to
ConcreteHandlers in the chain.
Consequences:
–
There is reduced coupling since the coin slot object does
not need to know the proper tube apriori. Although there are
4 tubes, only one slot is used. Receipt is not guaranteed.
Since there is no explicit receiver, the request may be
passed by all members in the chain. An attempt to put a
Canadian $2 coin in the bank would result in a coin that is
not put in any slot.
Chain of Responsibility
The Chain of Responsibility
is demonstrated in the
military, where some
underling asks for
approval and the request is
passed from superior to
superior until someone
finally makes a decision. If a
Seaman is asked for
permission to enter a Base,
he will likely forward the
request up the chain of
command.
Chain of Responsibility

Purpose
–

Participant Correspondence:
–

avoids coupling the sender of a request to the receiver.
The person asking permission to enter a Naval Base corresponds
to the client, since he is initiating the request. Each person in the
chain of command corresponds to ConcreteHandlers in the chain.
Consequences:
–
There is reduced coupling since the requester does not have to
know which person has the authority to grant the request. Such
knowledge would require that contact be made with the person in
authority. There is added flexibility in assigning responsibilities.
Based on the nature of the visit, the person with the appropriate
level of authority may change. The Seaman has the authority to let
a fellow sailor on the base, but not a newspaper photographer.
Receipt is not guaranteed. The client can only pose the request to
one member of the chain. Clients have no control over who
handles the request.
Chain of Responsibility Code (代号自动
生成器)
//这是抽象处理者角色
public interface CodeAutoParse {
//这里就是统一的处理请求使用的接口
String[] generateCode(String moduleCode, int number, String rule,String[] target
throws BaseException;
}
//这个为处理日期使用的具体处理者
public class DateAutoParse implements CodeAutoParse{
//获取当前时间
private final Calendar currentDate = Calendar.getInstance();
//这里用来注入下一个处理者,系统中采用Spring Bean管理
private CodeAutoParse theNextParseOfDate;
public void setTheNextParseOfDate(CodeAutoParse theNextParseOfDate){
this.theNextParseOfDate = theNextParseOfDate ;
}
/*
*实现的处理请求的接口
*这个接口首先判断用户定义的格式是否有流水号,有则解析,没有则跳过
*下传到下一个处理者
*/
public String[] generateCode(String moduleCode, int number, String rule, String[]
target) throws BaseException {
//这里省略了处理的业务
……
if(theNextParseOfDate != null)
return theNextParseOfDate.generateCode(moduleCode, number, rule,
target)
else
return target;
}
Command
The “check” at a
restaurant is used to
encapsulate the
customer’s order. The
waitress takes the order,
but it is the cook that
carries out the
Command. Since the
pad of “checks” can be
used by different
restaurants, they can
support many different
commands
Command

Purpose
–

Participant Correspondence:
–

allows requests to be encapsulated as objects, thereby allowing
clients to be parameterized with different requests.
The written order corresponds to the command. It creates a
binding between the cook and the action. The cook corresponds to
the receiver. He receives the order and is responsible for
executing it. The customer corresponds to the client. She creates
the command by placing an order. The waitress corresponds to the
invoker. She activates the command by placing it in a queue.
Consequences:
–
The object that invokes the command and the one that performs it
are decoupled. In the example, the waitress does not need to
know how to cook. Like the order, commands are first class
objects that can be manipulated and extended. At any time an
order can be modified. For example, the client may wish to add a
piece of pie to the order. Commands can be assembled into
composite commands. When several people at a table order on
the same check, the command is a composite.
Command Code (Struts)
public class Action {
……
/*
*可以看出,Action中提供了两个版本的执行接口,而且实现了默认的空实现。
*/
public ActionForward execute( ActionMapping mapping, ActionForm form,
ServletRequest request, ServletResponse response) throws Exception {
try {
return execute(mapping, form, (HttpServletRequest) request,
(HttpServletResponse) response);
} catch (ClassCastException e) {
return null;
}
}
public ActionForward execute( ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
return null;
}
}
public class RequestProcessor {
……
protected ActionForward processActionPerform(HttpServletRequest request,
HttpServletResponse response, Action action, ActionForm form,
ActionMapping mapping) throws IOException, ServletException {
try {
return (action.execute(mapping, form, request, response));
} catch (Exception e) {
return (processException(request, response,e, form, mapping));
}
}
}
Interpreter
Musical notation
provides a grammatical
representation for the
pitch and duration of
sounds. When
musicians play from a
score, they are
Interpreters, interpreting
that grammar.
Interpreter

Purpose
–

Participant Correspondence:
–

defines a grammatical representation for a language, and an interpreter to
interpret the grammar.
Musical notation corresponds to the abstract expression. Notes correspond
to terminal expressions. Each note indicates pitch and duration of the tone
to be played. Time and key signatures correspond to non terminal
expressions. On their own they cannot be interpretted. They do add
context, however. Knowing how to produce the proper sounds corresponds
to the context, or information global to interpreters. The musician interprets
the music, and therefore corresponds to the interpreter.
Consequences:
–
It is easy to change and extend the grammar. Existing expressions can be
modified to define new expressions. The sequence of three grace notes
preceding the “D” in the music above is readily recognizable as a “Hard D
Doubling” by Highland pipers. Similarities in nodes make implementation
easy. These similarities allow music to be transposed from one key to
another. It is easy to add new ways to interpret expressions. In music, the
dynamics change the interpretation of the piece.
Interpreter Code (加减乘除)
//上下文(环境)角色,使用HashMap来存储变量对应的数值
class Context{
private Map valueMap = new HashMap();
public void addValue(Variable x , int y){
Integer yi = new Integer(y);
valueMap.put(x , yi);
}
public int LookupValue(Variable x){
int i = ((Integer)valueMap.get(x)).intValue();
return i ;
}
}
//抽象表达式角色,也可以用接口来实现
abstract class Expression{
public abstract int interpret(Context con);
}
//终结符表达式角色
class Constant extends Expression{
private int i ;
public Constant(int i){
this.i = i;
}
public int interpret(Context con){
return i ;
}
}
class Variable extends Expression{
public int interpret(Context con) {
//this为调用interpret方法的Variable对象
return con.LookupValue(this);
}
}
//非终结符表达式角色
class Add extends Expression{
private Expression left ,right ;
public Add(Expression left , Expression right) {
this.left = left ;
this.right= right ;
}
public int interpret(Context con){
return left.interpret(con) + right.interpret(con);
}
}
class Subtract extends Expression{
private Expression left , right ;
public Subtract(Expression left , Expression right) {
this.left = left ;
this.right= right ;
}
public int interpret(Context con){
return left.interpret(con) - right.interpret(con);
}
}
public int interpret(Context con){
try{
return left.interpret(con) / right.interpret(con);
}catch(ArithmeticException ae) {
System.out.println("被除数为0!");
return -11111;
}
}
}
//测试程序,计算 (a*b)/(a-b+2)
public class Test {
private static Expression ex ;
private static Context con ;
public static void main(String[] args){
con = new Context();
//设置变量、常量
Variable a = new Variable();
Variable b = new Variable();
Constant c = new Constant(2);
//为变量赋值
con.addValue(a , 5);
con.addValue(b , 7);
//运算,对句子的结构由我们自己来分析,构造
ex = new Division(new Multiply(a , b), new Add(new Subtract(a , b) , c));
System.out.println("运算结果为:"+ex.interpret(con));
}
}
Iterator
The channel selector on
modern day television
sets is an example of an
Iterator. Rather than a
dial containing all
possible channels, or one
button per tuned
channel, today’s
television sets have a
Next and Previous
button for tuning
channels. The “Channel
Surfer” doesn’t need to
know if Channel 3 or
Channel 4 comes after
Channel 2.
Iterator

Purpose
–

Participant Correspondence:
–

provides ways to access elements of an aggregate object
sequentially without exposing the underlying structure of the object.
The channel selector corresponds to the iterator. The UP/DOWN
buttons on the remote control correspond to the concrete iterator.
The VHF channels 2-13, and UHF channels 14-83 correspond to
the aggregate. In any geographical area, all 82 broadcast
channels are not in use. The channels in use correspond to the
concrete aggregate.
Consequences:
–
Iterators support variation in the traversal of an aggregate. The
channel selection can traverse in ascending or descending order,
from any point in the aggregate. Iterators simplify the aggregate
interface. With modern channel selectors, a channel surfer can
traverse only the channels in use. With the old dials, every channel
had to be traversed whether in use or not.
Iterator
The receptionist in a doctor’s
waiting room iterates the
aggregate of patients who are
seated randomly around the
room. The receptionist will
send the “next” patient to the
doctor.
Iterator

Purpose
–

Participant Correspondence:
–

provides ways to access elements of an aggregate object
sequentially without exposing the underlying structure of the object.
The receptionist calling names in the doctor’s office corresponds to
the concrete iterator. The patients waiting in the doctor’s office
correspond to the concrete aggregate.
Consequences:
–
Iterators support variation in the traversal of an aggregate. The
receptionist can select the next patient based on arrival time,
appointment time or the severity of illness. Iterators simplify the
aggregate interface. Patients do not have to stand in a line in order
to be seen. More than one traversal can be pending on an
aggregate. If there are multiple doctors in the office, the
receptionist traverses the aggregate based on who the patient is
seeing. In effect, multiple traversals are occurring.
Iterator Code (Java Collection)
//迭代器角色,仅仅定义了遍历接口
public interface Iterator {
boolean hasNext();
Object next();
void remove();
}
//容器角色,这里以List为例。
//具体容器角色,便是实现了List接口的ArrayList等类。为了突出重点
这里指罗列和迭代器相关的内容
//具体迭代器角色,它是以内部类的形式出来的。AbstractList是为了
将各个具体容器角色的公共部分提取出来而存在的。
public abstract class AbstractList extends AbstractCollection
implements List { ……
//这个便是负责创建具体迭
public Iterator iterator() {
return new Itr();
}
//作为内部类的具体迭代器角色
private class Itr implements Iterator {
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public Object next() {
checkForComodification();
try {
Object next = get(cursor);
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch(IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
Mediator
The control tower at an
airport provides a central
point of communication
for aircraft in the terminal
area. Constraints on
terminal area airspace are
maintained by the tower.
With the centralized
communication and
constraint maintenance, the
tower behaves as a
Mediator.
Mediator

Purpose
–

Participant Correspondence:
–

defines an object that controls how a set of objects interact. Loose
coupling between colleague objects is achieved by having
colleagues communicate with the Mediator, rather than one
another.
Air Traffic Control corresponds to the Mediator. The specific tower
at an airport corresponds to the ConcreteMediator. Each arriving
and departing aircraft corresponds to the colleagues.
Consequences:
–
Constraints are localized within the Mediator. Changes to
constraints need only be dealt with in the tower. Aircraft will still
take off and land only when cleared to do so. Aircraft interactions
are decoupled. The many to many interactions are replaced with a
one to many interaction. Each aircraft communicates with the
tower, rather than with each other. Control is centralized in the
tower. Complexity of interaction between aircraft is traded for
complexity in the mediator.
Memento
There can be an infinite number of
settings for a piece of audio
mixing equipment. An engineer
could take a photograph of a
particular setting, and use the
photograph to restore the switch
settings to the desired state if
perturbed.
Memento

Purpose
–

Participant Correspondence:
–

captures and externalizes an object’s internal state, so the
object can be restored to that state later.
The mixing equipment corresponds to the original object,
whose state is being saved. The Photograph is the
memento. The engineer that takes the photo is the
originator. He will also use the memento to restore the state
of the switch settings. The drawer where the memento is
stored is the caretaker.
Consequences:
–
The photograph eliminates the need for everyone in the
studio to know the switch settings in case they are
perturbed. The photograph also stores information that the
engineer should manage, outside of the engineer (i.e. not in
his memory).
Memento
Most people are particular about
the radio station that they listen to
in the car. When there is more
than one driver, (Father, Mother,
Child), the radio station is likely to
have changed with the driver. The
preset buttons serve as mementos,
allowing the radio to be restored to
the desired tuning with one button
push.
Memento

Purpose
–

Participant Correspondence:
–

captures and externalizes an object’s internal state, so the
object can be restored to that state later.
The radio tuning corresponds to the original object, whose
state is being saved. The preset button is the memento. The
driver who sets the preset button is the originator. He will
also use the memento to restore the state of the radio
tuning. The radio where the button is located is the
caretaker.
Consequences:
–
The button eliminates the need for the drivers to memorize
the radi frequencies of their favorite stations. The preset
buttons store the information so that the tuning can be
restored.
Memento Code
class Originator{
private int state= 90; //这个是要保存的状态
private Caretaker c = new Caretaker(); //保持一个“备忘录管理者角色”的对象
//读取备忘录角色以恢复以前的状态
public void setMemento(){
Memento memento = (Memento)c.getMemento();
state = memento.getState();
System.out.println(“the state is ”+state+“ now”);
}
//创建一个备忘录角色,并将当前状态属性存入,托给“备忘录管理者角色”存放。
public void createMemento(){
c.saveMemento(new Memento(state));
}
//this is other business methods... they maybe modify the attribute state
public void modifyState4Test(int m){
state = m;
System.out.println("the state is "+state+" now");
}
//作为私有内部类的备忘录角色,它实现了窄接口,可以看到在第二种方法中
//宽接口已经不再需要
//注意:里面的属性和方法都是私有的
private class Memento implements MementoIF{
private int state ;
private Memento(int state){
this.state = state ;
}
private int getState(){
return state;
}
}
}
//测试代码——客户程序
public class TestInnerClass{
public static void main(String[] args){
Originator o = new Originator();
o.createMemento();
o.modifyState4Test(80);
o.setMemento();
}
}
//窄接口
interface MementoIF{}
//“备忘录管理者角色”
class Caretaker{
private MementoIF m ;
public void saveMemento(MementoIF m){ this.m = m; }
public MementoIF getMemento(){ return m; }
}
Observer
When a bidder at an
auction accepts a bid, he
or
she raises a numbered
paddle which identifies the
bidder. The bid price then
changes and all Observers
must be notified of the
change. The auctioneer
then broadcasts the new
bid to the bidders.
Observer

Purpose
–

Participant Correspondence:
–

defines a one to many relationship, so that when one object changes state,
the others are notified and updated automatically.
The auctioneer corresponds to the Subject. He knows the observers, since
they must register for the auction. The current bid corresponds to the
ConcreteSubject The observers are most interested in its state. The
bidders correspond to the Observers. They need to know when the current
bid changes. Each individual bidder with different tolerances for the bidding
correspond to the ConcreteObservers.
Consequences:
–
There is abstract coupling between the subject and observers. All that the
auctioneer knows is that bidders will bid. He does not know when the price
will become too steep for an individual bidder. There is support for
broadcast communication. When the auctioneer announces the current bid,
that information is broadcast to all interested parties. Observers can cause
an avalanche of unexpected updates, since they can be blind to the
ultimate cost of changing the subject. A bidder ma y intend to raise the bid
by $50, and end up starting a bidding war.
Observer
Consumers who register
for a product warranty are
like observers. When the
safety record of the
product changes (like in a
recall), all registered
observers are notified.
Observer

Purpose
–

Participant Correspondence:
–

defines a one to many relationship, so that when one object changes state,
the others are notified and updated automatically.
The company corresponds to the Subject. It knows the observers, since
they must register for the warranty. The product safety/reliability record
corresponds to the ConcreteSubject The observers are most interested in
its state. The consumers correspond to the Observers. They need to know
when the current product safety/reliability record changes. Each individual
consumer corresponds to the ConcreteObservers, since they will have
different experiences with the product.
Consequences:
–
There is abstract coupling between the subject and observers. All that the
company knows is that consumers have registered for the warranty. It does
not know which once will require warranty service. There is support for
broadcast communication. If a recall occurs, a form letter is sent out to all
registered owners. Observers can cause an avalanche of unexpected
updates, since they can be blind to the ultimate cost of changing the
subject. Consumers trying to obtain warranty service are not aware of
other consumer’s experience with the product. If enough claims are
submitted, the product may be recalled.
Observer Code (JUnit)
//下面是我们的抽象观察者角色,JUnit是采用接口来实现的,这也是一般采用的方式。
//可以看到这里面定义了四个不同的update方法,对应四种不同的状态变化
public interface TestListener {
//An error occurred.
public void addError(Test test, Throwable t);
//A failure occurred.
public void addFailure(Test test, AssertionFailedError t);
// A test ended.
public void endTest(Test test);
//A test started.
public void startTest(Test test);
}
//具体观察者角色,我们采用最简单的TextUI下的情况来说明
public class ResultPrinter implements TestListener {
……
//下面就是实现接口TestListener的四个方法
//see junit.framework.TestListener#addError(Test, Throwable)
public void addError(Test test, Throwable t) {
getWriter().print("E");
}
//see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
public void addFailure(Test test, AssertionFailedError t) {
getWriter().print("F");
}
//see junit.framework.TestListener#endTest(Test)
public void endTest(Test test) {
}
//see junit.framework.TestListener#startTest(Test)
public void startTest(Test test) {
getWriter().print(".");
if (fColumn++ >= 40) {
getWriter().println();
fColumn= 0;
}
}
}
public class TestResult extends Object {
//这个是用来存放测试Failures的集合
protected Vector fFailures;
//这个就是用来存放注册进来的观察者的集合
protected Vector fListeners;
public TestResult() {
fFailures= new Vector();
fListeners= new Vector();
}
// Adds a failure to the list of failures. The passed in exception
//caused the failure.
public synchronized void addFailure(Test test, AssertionFailedError t) {
fFailures.addElement(new TestFailure(test, t));
//下面就是通知各个观察者的addFailure方法
for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
((TestListener)e.nextElement()).addFailure(test, t);
}
}
// 注册一个观察者
public synchronized void addListener(TestListener listener) {
fListeners.addElement(listener);
}
// 删除一个观察者
public synchronized void removeListener(TestListener listener) {
fListeners.removeElement(listener);
}
/**
* 返回一个观察者集合的拷贝,当然是为了防止对观察者集合的非法方式操作了
* 可以看到所有使用观察者集合的地方都通过它
*/
private synchronized Vector cloneListeners() {
return (Vector)fListeners.clone();
}
……
}
public class TestRunner extends BaseTestRunner {
private ResultPrinter fPrinter;
public TestResult doRun(Test suite, boolean wait) {
//就是在这里注册的
result.addListener(fPrinter);
……
State
The behavior of a vending
machine varies based on its
State. The currency on
deposit, the product
inventory, the selection,
and the currency in the
change bank are all part of
the vending machine’s
State.
State

Purpose
–

Participant Correspondence:
–

allows an object to change its behavior when its internal
state changes.
The deposit on hand, stock, and change on hand
correspond to the context. The behavior associated with
each context corresponds to the state.
Consequences:
–
Behavior specific to a given state is localized. When the
machine runs out of potato chips, the exact change light will
not be illuminated, unless exact change is required. State
transitions are explicit. Product A will not be delivered
unless the deposit on hand is sufficient for Product A.
Strategy
Faxing, overnight mail, air
mail, and surface mail all get
a document from one place
to another, but in different
ways.
Strategy

Purpose
–

Participant Correspondence:
–

defines a set of algorithms that can be used interchangeably.
Text based communication corresponds to the Strategy. Specific
forms of text base communication, such as fax, mail, etc.
correspond to the ConcreteStrategies. The context in which
textural information is conveyed corresponds to the Context.
Consequences:
–
Strategies combine families of related algorithms. There are
several ways to send textual information. Strategies allow the
algorithm to vary independently of the context. For example, if
textual information must be delivered to the next office, placing on
copy on your colleague’s chair is a valid algorithm, but e-mail could
also be used. The proximity does not necessarily dictate the
algorithm. Strategies offer a choice of implementations.
Strategy
There are many modes of
transportation to and from
an airport. Choosing a
particular transportation
Strategy involves making
tradeoffs between cost,
time, and convenience.
Strategy

Purpose
–

Participant Correspondence:
–

defines a set of algorithms that can be used interchangeably.
Transportation to the airport corresponds to the Strategy.
Specific forms of transportation such as bus, taxi, etc.
correspond to the ConcreteStrategies. The context in which
one must get to the airport (rush hour, maximum
convenience, etc.) corresponds to the Context.
Consequences:
–
Strategies combine families of related algorithms. There are
several ways to get to the airport. Strategies allow the
algorithm to vary independently of the context. The context
alone does not dictate which method of transportation will
be used. Strategies offer a choice of implementations.
Strategy Code
先来看看Container中有关的代码:
LayoutManager layoutMgr; //对布局管理器接口的引用
//获得在使用的具体布局管理器
public LayoutManager getLayout() {
return layoutMgr;
}
//设置要使用的具体布局管理器
public void setLayout(LayoutManager mgr) {
layoutMgr = mgr;
if (valid) {
invalidate();
}
}
可以看到,Container根本就不关心你使用的是什么具体的布局管理器,这样也就使得
Container不会随着布局管理器的增多而修改本身。所以说策略模式是对变化的封装。
下面是布局管理器接口的代码:
public interface LayoutManager {
void addLayoutComponent(String name, Component comp);
………
Dimension minimumLayoutSize(Container parent);
void layoutContainer(Container parent);
}
使用,以下是示意性代码:
public class FlowLayoutWindow extends JApplet {
public void init() {
Containter cp = getContentPane();
cp.setLayout(new FlowLayout());
for(int i = 0 ; i < 20 ; i++)
cp.add(new JButton("Button" + i));
}
......
}
Template Method
Subdivision developers
often use a Template
Method to produce a
variety of home models
from a limited number of
floor plans. The basic
floor plans are a skeleton,
and the differentiation is
deferred until later in the
building process.
Template Method

Purpose
–

Participant Correspondence:
–

defines a skeleton of an algorithm in an operation, and
defers some steps to subclasses.
The basic floor plan corresponds to the AbstractClass. The
different elevations correspond to the ConcreteClasses.
Consequences:
–
Templates factor out what is common, so that it can be
reused. Multiple elevations can be built from a basic floor
plan. The specific elevation does not need to be chosen
until later in the process.
Template Method
Once a basic bread recipe
is developed, additional steps,
such as adding cinnamon,
raisins, nuts, peppers, cheese,
etc. can be used to create
different types of bread.
Template Method

Purpose
–

Participant Correspondence:
–

defines a skeleton of an algorithm in an operation,
and defers some steps to subclasses.
The basic bread recipe corresponds to the
AbstractClass. The additions to make the bread
distinctive correspond the the ConcreteClass.
Consequences:
–
Templates factor out what is common. Multiple
bread recipes can have a basic recipe in common.
Template Method Code(JUnit)
//这是TestCase中,执行测试的模板方法。你可以看到,里面正像前面定义中
//所说的那样。它制定了“算法”的框架——先执行setUp方法来做下初始化,然
//后执行测试方法,最后执行tearDown释放你得到的资源。
public void runBare() throws Throwable {
setUp();
try {
runTest();
} finally {
tearDown();
}
}
这两个方法并没有被实现为抽象方法,而是两个空的无为方法(被称为钩子方法)。
这是因为在测试中,我们并不是必须要让测试程序使用这两个方法来初始化和释放
资源的。如果是抽象方法,则子类们必须给它一个实现,不管用到用不到。这显然
是不合理的。使用钩子方法,则你在需要的时候,可以在子类中重写这些方法。
protected void setUp() throws Exception { }
protected void tearDown() throws Exception { }
Visitor
An outside consultant
coming into a department,
to meet with everyone in
the department on a one-on-one
basis is an example of
Visitor. While the visitor is
escorted to each cubicle,
she does nothing. Once she
arrives at a cubicle, she
springs into action
interviewing the employee
(sending messages and
obtaining results).
Visitor

Purpose
–

Participant Correspondence:
–

represents an operation to be performed on the elements of an object
structure, without changing the classes on which is operates.
The consultant corresponds to the Visitor. The consultant also corresponds
to the ConcreteVisitor, but purpose of the visit determines the
ConcreteVisitor. The element corresponds to the office visited. The
employee occupying the office corresponds to the ConcreteElement. The
schedule or agenda of the visit corresponds to the ObjectStructure.
Consequences:
–
The visitor makes adding new operations easy. By adding a new visitor,
new operations can be added. For example, a survey visitor may be
dispatched to survey employees. Once management finds out that they are
stressed, a masseuse visitor may be sent around to relieve stress. Visitors
gather related operations, and separate unrelated ones. The engineering
department is not typically involved in employee attitude surveys. It makes
more sense to have a visitor, rather than an engineer conduct these.
Visitors often break encapsulation. In the real world, consultants are
required to sign non-disclosure agreements, because encapsulation gets
broken.
Visitor Code
//访问者角色
interface Visitor {
void visit(Gladiolus g);
void visit(Runuculus r);
void visit(Chrysanthemum c);
}
// The Flower hierarchy cannot be changed:
//元素角色
interface Flower {
void accept(Visitor v);
}
//以下三个具体元素角色
class Gladiolus implements Flower {
public void accept(Visitor v) { v.visit(this);}
}
class Runuculus implements Flower {
public void accept(Visitor v) { v.visit(this);}
}
class Chrysanthemum implements Flower {
public void accept(Visitor v) { v.visit(this);}
}
// Add the ability to produce a string:
//实现的具体访问者角色
class StringVal implements Visitor {
String s;
public String toString() { return s; }
public void visit(Gladiolus g) {
s = "Gladiolus";
}
public void visit(Runuculus r) {
s = "Runuculus";
}
public void visit(Chrysanthemum c) {
s = "Chrysanthemum";
}
}
// Add the ability to do "Bee" activities:
//另一个具体访问者角色
class Bee implements Visitor {
public void visit(Gladiolus g) {
System.out.println("Bee and Gladiolus");
}
public void visit(Runuculus r) {
System.out.println("Bee and Runuculus");
}
public void visit(Chrysanthemum c) {
System.out.println("Bee and Chrysanthemum");
}
}
//这是一个对象生成器
//这不是一个完整的对象结构,这里仅仅是模拟对象结构中的元素
class FlowerGenerator {
private static Random rand = new Random();
public static Flower newFlower() {
switch(rand.nextInt(3)) {
default:
case 0: return new Gladiolus();
case 1: return new Runuculus();
case 2: return new Chrysanthemum();
}
}
}
//客户测试程序
public class BeeAndFlowers extends TestCase {
/*
在这里你能看到访问者模式执行的流程:
首先在客户端先获得一个具体的访问者角色
遍历对象结构
对每一个元素调用accept方法,将具体访问者角色传入
这样就完成了整个过程
*/
//对象结构角色在这里才组装上
List flowers = new ArrayList();
public BeeAndFlowers() {
for(int i = 0; i < 10; i++)
flowers.add(FlowerGenerator.newFlower());
}
Visitor sval ;
public void test() {
// It's almost as if I had a function to
// produce a Flower string representation:
//这个地方你可以修改以便使用另外一个具体访问者角色
sval = new StringVal();
Iterator it = flowers.iterator();
while(it.hasNext()) {
((Flower)it.next()).accept(sval);
System.out.println(sval);
}
}
public static void main(String args[]) {
junit.textui.TestRunner.run(BeeAndFlowers.class);
}
}
Examples to Accompany:
Pattern-Oriented Software
Architecture
Layers
The Layers pattern helps
structure applications that can
be decomposed into groups
of subtasks at different layers
of abstraction. Consider
shipping a bike. The person at
the shipping or receiving end
of the process, or the driver
may not know how to
assemble or disassemble a
bike. Then again, they don’t
need to know how.
Layers

Purpose
–

Participant Correspondence:
–

structure applications that can be decomposed into different
subtasks, with each subtask at an appropriate level of abstraction.
When considering disassembling a bike for transport, and
reassembling it at its destination, each step corresponds to a layer.
The disassembly/assembly, packing/unpacking, shipping/receiving
are all tasks at different levels of abstraction.
Consequences:
–
The layers are exchangeable. The disassembler, packer, or
shipping clerk can be changed without altering the basic structure
of the example. Layers can be used in a variety of context. The
packer and pack items other than bicycles, just as the shipping
clerk can ship items other than bicycles. Dependencies are kept
local. If a bike requires non-metric tools, the packing/unpacking
and shipping/receiving layers are not impacted.
Pipes and Filters
Public water systems demonstrate
Pipes and Filters. The water
flowing through pipes is the
input to a filter. Pipes are also used
as the output from a filter. This
example shows that name
correspondence between the
example and pattern can produce a
viable example.
Pipes and Filters

Purpose
–

Participant Correspondence:
–

provides a structure for systems that process a stream of
data.
In the public water system example, the water pipes
correspond to data pipes. The various stages that add
something to or take something from the water correspond
to the filters.
Consequences:
–
Changing filters adds flexibility. For example, fluoride could
be added to the water supply without upsetting the overall
system. Recombining filters adds flexibility. Many homes
have water treatment systems that soften water used for
cleaning and filter chemicals from the drinking water. All of
these home systems take advantage of water supplied via
the upstream pipes and filters.
Blackboard
Watch just about any police
show on television, and
notice that the crimes cannot
be solved immediately.
There is often a blackboard
with forensic evidence,
ballistic reports, crime scene
data, etc. posted. When all
of the experts add their
pieces of the puzzle, the
police are able to solve the
crime!
Blackboard

Purpose
–

Participant Correspondence:
–

assemble knowledge from a variety of sources when no
deterministic solution strategy is known.
Obviously the blackboard corresponds to the blackboard class
(where data is centrally managed). Each person having subject
matter expertise corresponds to a knowledg source. The lead
detective is the controller, who brings together the subject matter
experts, and manages access to the blackboard.
Consequences:
–
It is easy to experiment with different approaches when data from
different sources is brought together. It is easy to change and
maintain the blackboard, because the independence between the
participants. If a crime involved a knife, there would be no need to
involve a ballistics subject matter expert. A blackboard is robust.
Only conclusions supported by data and other hypothesis survive.
All others are weeded out.
Broker
A travel agent is a broker for
travel related services. A
customer dealing with a
travel agent can book
passage on ships, planes and
trains, reserve a hotel room
and rental car, and book
tours. The customer deals
only with the travel agent,
although several companies
are involved. Note that
there are often complex
codes on the itinerary. The
broker and travel services
companies understand these
codes. The customer often
does not.
Broker

Purpose
–

Participant Correspondence:
–

structure distributed systems with decoupled components that
interact by remote service invocations. The Broker component is
responsible for coordinating communication between clients and
servers.
The Travel Agent’s client corresponds to the Client. The Travel
Agent corresponds the Broker. The Travel Services, such as
airlines, rental cars, hotels, etc. correspond to the Servers. The
reservation systems for the Travel Services correspond to the
Server-side Proxies.
Consequences:
–
The Travel Agent, like the Broker offers location transparency. The
client does not need to know where particular travel services are
located. If a server changes, the interface is the same to the client.
The interface is the same to the client, regardless of the airline
booked. Details of internal systems are hidden. A travel agent
switching from SABRE to APOLLO reservation system is
transparent to the client.
Model-View-Controller
Some types of dancers are
known to pay special attention
to those who tip the highest.
In this situation, the dancer is
the model, and whoever is
tipping is controlling the view
of the model for himself, as
well as all others.
Model-View-Controller

Purpose
–

Participant Correspondence:
–

divides an interactive application into a model (or core data),
view (display) and controller.
The dancer corresponds to the model. The view of the
dancer from different vantage points corresponds to the
view of the model. The big tipper, corresponds to the
controller, since the view of the model changes while he is
getting special attention.
Consequences:
–
With a dancer, there are multiple views of the same model.
These views are synchronized, since the view of a model is
changing simultaneously as she walks away from one
observer, and towards another.
Presentation-Abstraction-Control
Polls will often gather
information from all over
the country, and display
results as national totals,
regional totals, state totals
and city totals. The
information is gathered at
each site, and then reported
to a central site.
Presentation-Abstraction-Controller

Purpose
–

Participant Correspondence:
–

defines a structure for interactive systems in the form of a
hierarchy of cooperating agents. Each agent is responsible for a
specific aspect of the application’s functionality.
The national data repository corresponds to the Top-level Agent. It
controls the PAC hierarchy. The regional and state data
repositories correspond to the Intermediate-level Agents. The city
data repositories correspond to the Bottom-level Agents.
Consequences:
–
Detailed information can be obtained from each level. A synopsis
of voter behavior for a city can be obtained at the city level. The
model is easily extendible. A county agent can be added between
the city and state level, without impacting the regional and national
levels. Multi-tasking is supported. Voter behavior for multiple cities
can be examined simultaneously.
Microkernel
Nintendo makes a GameboyTM
hand-held video game. The
Gameboy unit provides the
core functionality, such as
displays and input/output for
numerous games and the
Gameboy camera. A game
cartridge or the Gameboy
camera can be inserted to
allow the user to play.
Microkernel

Purpose
–

Participant Correspondence:
–

separates the minimal functional core from extended functionality.
The player corresponds to the client. The GameboyTM unit
corresponds to the microkernel, since it contains the core
functionality. The game cartridges correspond to the internal
servers, which provide additional functionality. The pin connections
on the unit and cartridges correspond to the adapter. The buttons
on the unit provide an interface to clients, and therefore
correspond to the external server.
Consequences:
–
The client applications can be easily shared between hardware
without porting to a new environment. Kids can trade game
cartridges without violating software copyrights. The Gameboy is
very flexible. Originally it was only for games. Eventually, it could
be used as a camera. The Gameboy has separated policy and
mechanism, so that new external servers could be added that
implement their own views. For example, on the Gameboy camera
cartridge, the lens is a new external server.
Reflection
Reflection provides a
mechanism for changing
structure and behavior
dynamically. Consider a
constitution. Changing the
behavior of a legislative body is
done by changing the
constitution. The constitution
can be considered to be a
metaobject,
while the legislative
body is the base object.
Reflection

Purpose
–

Participant Correspondence:
–

provides a mechanism for changing structure and behavior of a system
dynamically. A system is structured as a base level, and meta level. The
meta level contains information about system properties. The base level
exhibits the application structure and behavior. Changes to meta level
information affect subsequent base level structure and behavior.
The Constitution corresponds to the meta level. It contains information on
how the congress is to conduct itself. The congress is the base level. It
conducts itself according to the Constitution. Changes to the Constitution
affect how the congress behaves.
Consequences:
–
There is no explicit modification of the base. A change is accomplished by
calling a function in the metaobject protocol. For example, the makeup of
congress changes every two years due to elections as outlined in the
Constitution. Change to the system is easy. The Constitution provides safe
and uniform mechanism for changing the congress. Many types of change
are supported. Looking at the types of change that have can affect the
structure of congress, elections, representation based on census, and
adding a new state can cause changes in structure. Meta level changes
can damage the system, just as changes to the Constitution can cause
damage.
Whole-Part
A car encapsulates many parts
that a driver cannot access
directly. While driving, the
fuel injector will supply fuel to
the cylinder, the distributor
will provide spark to the
sparkplug in that cylinder, the
sparkplug will fire, and the
piston will be forced down,
thereby turning the cam. The
driver has no direct access to
any of these parts.
Whole-Part

Purpose
–

Participant Correspondence:
–

helps aggregate components that form a semantic unit.
The driver corresponds to the client. The driver will ultimately use
all of the components through the interface of the whole. The car
corresponds to the Whole. It is made up of smaller systems. The
individual systems, such as the fuel system, ignition system,
cooling system, etc. correspond to the Parts.
Consequences:
–
Parts are changeable without impacting the client. If a starter fails,
it can be replaced, and the interface to the care remains the same
for the driver. Each concern is implemented by a separate part,
making it easier to implement complex strategies. Many of the
parts on a car are fairly simple, yet the composite is quite complex.
Reusability is supported since parts of a whole can be used in
other aggregates. The auto salvage industry is build on this
concept. A part can be taken from one car for use on another.
Master-Slave
When tasked with taking
the census, the Census
Bureau utilizes census
takers. The census takers
are semantically the same,
(a census taker for one area
could just a easily work a
different area), and the
results are tabulated by the
Census Bureau. Any
“clients” of the Census
Bureau deal directly with
the Bureau, and not with
the individual census
takers.

Purpose
–

Participant Correspondence:
–

A master component distributes work to identical slave
components and computes a final result from the results when the
slaves return
The congress corresponds to the client. Congress authorizes the
census, and uses its results. The Census Bureau corresponds to
the Master. It is responsible for taking the census, and does so by
dividing the work into smaller tasks. The Census takers
correspond to the Slaves. They report the work to the Census
Bureau. They are interchangeable.
Consequences:
–
Makes slaves exchangeable and extensible. A census taker can
cover any designated area. If one finishes early, he can be
reassigned to another area. Separates slave and client code from
the work partitioning code. Neither congress or the individual
census takers are concerned with how work is partitioned. Allows
for parallel computing. With multiple census takers, they can all be
working simultaneously. There is no need to finish one area before
starting another.
Proxy
Many organizations offer a
proxy e-mail address. When
someone sends mail to a
proxy address, he or she
may have no idea that it is a
proxy address. The proxy
then forwards the message
to the “real” e-mail address.

Purpose
–

Participant Correspondence:
–

provides a surrogate or place holder to provide access to an object.
The organization e-mail address corresponds to the Proxy. The
“real” e-mail address corresponds to the Original. The individual
having the proxy e-mail and original e-mail address corresponds to
the AbstractOriginal. The person sending e-mail to the
AbstractOriginal corresponds to the Client.
Consequences:
–
The proxy introduces a level of indirection when accessing an
object. The indirection can be used for security, or disguising the
fact that an object is located in a different address space. In the
case of the e-mail example, the AbstractOriginal can change real
e-mail addresses (like when changing companies) and still receive
e-mail through the proxy.
Command Processor
In catalog sales, orders can
be received by Mail, Phone,
or FAX. When a request is
received, an order is
generated. The order will
cause items to be removed
from stock in order to fill
the order. If an order is
returned, the item will be
returned to stock, and the
account will be credited. If
a web site based order form
is implemented, the basic
order processing will
remain intact.
Command Processor

Purpose
–

Participant Correspondence:
–

separates the request for a service from its execution.
The Customer Interface corresponds to the Controller. The Order
Fulfillment department corresponds to the Command Processor.
This department is responsible for processing the order, making
sure that an item is taken from stock, and sent to the customer. If
the item is returned, the order fulfillment department will return the
item to stock. The order corresponds to the Capitalize command.
Once a phone call, order form, or fax is received, it becomes a
record is created containing the customer name, address, desired
items, and method of payment. The inventory corresponds to the
supplier.
Consequences:
–
There is flexibility in the way that requests are activated. A
customer can order via mail, phone, or FAX. If a web site based
order form is implemented, the basic order processing will remain
intact. Commands can be implemented concurrently. Several
customers will request items daily. The orders are placed in bins,
and shipped when complete.
View Handler
Although window managers
are common to software, the
visual nature of windows
allows one to examine
behavior without looking at
source code. The window
manager opens, manipulates,
and disposes of views. It also
coordinates dependencies
between views, and
coordinates their updates.
View Handler

Purpose
–

Participant Correspondence:
–

helps manage all views provided by a system.
The windowing system corresponds to the view
handler. The displayed windows correspond to
the views. The underlying files or documents
correspond to the supplier(s)
Consequences:
–
The View Handler provides uniform handling of
views. New views can be added without affecting
existing views.
Forwarder-Receiver
School children often use the
Forwarder-Receiver pattern.
Johnny will write a message to
Judy, fold it, pass it to Mary, and
ask her to pass it to Judy.
Mary will pass it to Billy, and ask
him to pass it to Judy.
Billy will pass it to Judy, who
will unfold the message and read
It.
Forwarder-Receiver

Purpose
–

Participant Correspondence:
–

introduces a peer-to-peer communication model that decouples
the forwarders and receivers from the underlying communication
mechanisms.
Each student corresponds to a peer. Students will act as
Forwarders when they pass a note, and Receivers when they
receive the note.
Consequences:
–
Note passing is efficient inter-process communication. A forwarder
knows the location of potential receivers, but does not need to
know the location of the ultimate destination. A change in
communication mechanism does not impact forwarders and
receivers. For instance, if the note were written in French, it would
still be passed in the same manner.
Client-Dispatcher-Server
When a client calls a company
to talk with an individual, a
receptionist often answers the
call, and then routes it to the
appropriate person. The client
cannot tell if the person is in
the same building, or at a
remote site. Furthermore, the
client does not know if the
phone rings on the sales
manager’s desk, or if the
receptionist puts him on hold,
and yells, “Hey Larry, pick up
the phone!”
Client-Dispatcher-Sever

Purpose
–

Participant Correspondence:
–

introduces an intermediate layer between clients and
servers to provide location transparency and hide
connection details.
The customer corresponds to the Client. The receptionist
corresponds to the Dispatcher. The sales manager (or
anyone else being called) corresponds to the server.
Consequences:
–
The Client-Dispatcher-Server introduces an intermediate
layer between clients and servers. It provides location
transparency, by means of a name service. It hides the
details of the communication connection between clients
and servers. If a new sales manager is hired, the customer
is not required to have this knowledge in order to reach him.
Publisher-Subscriber
To communicate to others,
one can post or publish a
notice on a bulletin board.
The subscribers (readers) of
the bulletin board can vary
dynamically. State
information, such as having
extra tickets can be
communicated to unknown
individuals when it is not
feasible to poll people
explicitly to determine if
they require the tickets.
Publisher-Subscriber

Purpose
–

Participant Correspondence:
–

helps to keep the state of cooperating agents synchronized.
A publisher notifies any number of subscribers of changes
in state.
Someone posting a message on a bulletin board
corresponds to the publisher. Someone reading the bulletin
board corresponds to a subscriber.
Consequences:
–
Changes in state must be communicated to unknown
parties. The number of subscribers can vary dynamically.
When an individual needs tickets to an event, a message is
posted indicating that their state is “NeedTickets”. When
tickets are obtained, the message is removed.
Download