设计模式简要总结——结构型模式
2016-04-15 15:40
309 查看
1. adapter 适配器
应用: 一个通用的接口,希望使用一个已有的类。
原理:定义一个抽象的接口(或者目标类),总之是应用程序使用的类。这个类定义应用程序使用功能的接口原型。
但是目标类并不具备某些功能,而需要使用已有的另一个类。
这时可以有两种方法:
a 定一个类公有继承自目标类,同时私有继承自一个adaptee(提供功能的类)。在这个类里面使用已有类的功能。 多重类继承方式。
b 定一个类继承自目标类,同时引用一个已有类的实例。 对象组合方式。
2. ★ bridge 桥接
挺有用的一个模式。
应用:如果一个类定义了抽象接口,并且可以派生出子类来实现。 而这些子类的实现过程,又是希望可变化(比如在不同平台上实现)。
原理:一个抽象的类定义应用程序的接口。抽象类中持有一个imp类的引用,具体类中通过函数(用工厂方法)获取这个引用,并
使用这个引用提供的方法。
从实现过程可以看出,bridge是在对抽象接口的实现过程时,又做了一次抽象,来达到具体类的实现过程可变。
_imp像桥一样连接了应用抽象接口的实现 和 具体的实现过程。
手法就是一个组合,或委托。
实现:
class Window{
virtual void DrawContents();
protected:
WindowImp * GetWindowImp();
private:
WindowImp * _imp;
} ;
WindowImp * Window::GetWindowImp()
{
return Factory.Instance().MakeWindowImp(); ///////////在这里根据条件判断跨windows平台。
}
class IconWindow: Window
{
void DrawContents()
{
_imp = GetWindowImp();
_imp->DeviceRect();
}
};
class WindowImp{
virtual void DeviceRect() = 0;
};
class XWindowImp : public WindowImp
{
void DeviceRect()
{
xxxxxxxxxxxxxxx;
}
};
class PMWindowImp : public WindowImp
{
void DeviceRect()
{
xxxxxxxxxxxxxxx;
}
};
3. composite 组合
4. decorator 装饰(包装机)
应用: 以动态、透明的方式给一个对象添加职责
当不方便用继承的方式进行功能扩充时。例如有大量独立的扩展,每一种组合将产生大量的子类。
原理:为实际对象增加一个外壳,在外壳里面添加需要扩展的功能。
外壳与实际对象需要使用一个相同的对外接口,使得应用程序看不到外壳的存在。
所以,外壳是继承自一个抽象接口的,实际对象也继承自同一抽象接口。
由于外壳里面持有的实际对象可以在运行时刻变化,使得外壳(包装)与实际对象之间的交叉组合成为可能。
实现:
class VisualComponent{
virtual void Draw();
};
class Decorator: public VisualComponent ///////定义包装机的接口。并将被包装的具体对象引用放到了这里。
{
Decorator(VisualComponent * c):_component(c){}
virtual void Draw()
{
c->Draw();
}
private:
VisualComponent * _component;
};
class ConceretComponent : public VisualComponent/////////// 具体的对象
{
void Draw()
{
XXXXXX;
}
};
class ConceretDecorator:public Decorator /////////// 为对象增加的外壳之一。
{
void Draw()
{
xxxxxxxxx do some thing for conceret decorator;
Decorator::Draw();
}
};
////////////应用程序:
c = new ConceretDecorator(new ConceretComponent) ///// 这样就可以实现外壳与被包装之间的组合。可以避免以继承的方式进行静态扩展,带来的子类泛滥。
c->Draw();
相关模式: 适配器是希望利用现有对象,达到通用接口希望的功能,即把现有对象转化成另一个接口。
装饰是希望改变对象的职责,不改变他的接口。装饰使用对象的出发点还是现有对象,只在上面加一点附加(修饰)功能。
在实现手法上,装饰与桥接有点相似。他们的不同在于桥接的imp类的接口可以完全与具体类(应用程序调用的)接口不同。
桥接的本质是经过一次组合(或委托),将抽象接口的实现过程中可能出现的变化抽象到一个抽象接口上面去。
装饰则是两个类(已有对象与包装)都有各自的功能,应用程序希望在已有对象上面增加一定职责,并且希望灵活变化(如果固定的使用一个继承就完成扩展了)。
装饰的本质是在已有对象外面报个壳子(实现一些功能),把壳子交给应用程序使用,并且使应用程序认为这就是自己。在壳子的实现里面将功能再委托给已有对象。
通过可以灵活的更换壳子和已有对象的组合,达到扩展。
5. facade 外观
原理: 他为一个子系统、或一个提供功能的代码库设计一个应对一般情况的简化接口,使得应用程序不用看到子系统的全部细节接口。当然,如果应用
程序有更个性化的需求希望看到子系统内部接口,依旧允许看到。
他的好处是对应用程序屏蔽了复杂子系统内部庞杂的类、以及他们的互相配合关系,使得子系统的演化不影响应用程序。
他的应用是对一个庞大的库进行针对某些特定功能的封装,提供出接口。
实现:
class Scanner{
void Scan();
};
class Parser{
void Parse();
};
class Compiler{ //////////////这是一个facade。 他把编译子系统里面的部件集成到一起。提供一个简单的接口compile供应用程序使用。
void compile()
{
Scaner scan;
Parser parser;
scan.Scan();
parser.Parse();
xxxxxxxxxxxxxxx;
}
};
6. flyweight 享元
应用: 对那些通常因为数量太大而难以用对象来表示的概念或实体进行建模。
由于面向对象的编程所有东西都是对象,因此可能系统中需要创建大量的对象。比如:文档中的每一个字是一个对象。
使用条件:
一个应用程序使用了大量的对象
对象的大多数状态都可以变为外部状态
如果删除对象的外部状态,可以用相对较少的共享对象取代很多组对象
应用程序不依赖于对象标识。
原理: 区分出对象的内部状态和外部状态。 内部状态是可共享的,外部状态是可变的。
因内部状态可共享的特点,可以将很多对象用较少的共享对象来表示,在使用时临时增加响应的外部状态。
应用程序维持一个对flyweight的引用,同时计算或存储flyweight的外部状态。
flyweight通常与工厂方法一起使用,通过工厂维护较少量、可共享的flyweight对象。
实现:
class FlyWeight{
virtual void Operation(const string& extrinsicState);
void DosthforintrinsicState()
{
cout<<_intrinsicState<<endl;
}
protected:
FlyWeight(string intrinsicState):_intrinsicState(intrinsicState){}
private:
string _intrinsicState;
};
class ConceretFlyWeight : public FlyWeight
{
ConceretFlyWeight(string intrinsicState):FlyWeight(intrinsicState){}
void Operation(const string& extrinsicState)
{
this->DosthforintrinsicState(); /////////共享的内部状态
dosthforextrinsicState(extrinsicState); /////////可变的外部状态
}
}
class UnSharedFlyWeight: FlyWeight
{
void Operation(const string& extrinsicState)
{
doXXX(extrinsicState);
}
};
class FlyWeightFactory
{
FlyWeight * getFlyWeight(string key)
{
if(_exist(key))
{
return existing flyweight;
}
else
{
new FlyWeight(key);
add FlyWeight to pool of flyweights;
return the new flyweight;
}
}
};
app:
{
define a extrinsicState;
FlyWeight * fly = FlyWeightFactory::getFlyWeight(key);
fly.Operation(extrinsicState);
}
7. proxy 代理
原理: 代理对象持有一个实际对象的引用(这种方法和decorator类似)或持有一个可创建实际对象的标识,在代理对象实例化
的时候并不创建实际对象,等到使用的时候再创建。(virtual proxy模型)
或需要访问远程(或另一地址空间)的变量时(remote proxy模型)
或打算在访问实际对象时做一点事情(protection proxy模型),比如判断是否具有权限。这个模型写法类似decorator。
应用:当对象很大,不想在初始化的时候就创建所有对象,希望使用时再创建。
实现:
class Graphic
{
virtual void Draw() = 0; //////
};
class Image:public Graphic /////实际执行动作的类
{
void Draw()
{
xxxx;
实际的执行动作;
}
};
class proxy:public Graphic ////virtual proxy 代理,负责在需要创建实际对象时再创建
proxy(string filename):_filename(filename),_image(0){}
void Draw()
{
getImage()->Draw();
}
Image * getImage()
{
if(_image == 0)
{
_image = new Image(_filename);
}
}
private:
string _filename;
Image * _image;
};
class ProtectionProxy ////////Protection Proxy形式的proxy.
{
if(msg is legal)
{
getImage()->dothings();
}
else
{
getImage( doesnotunderstand_msg);
或者直接返回false;
cout<<"msg is error<<endl;
return false;
}
};
总结:adapter用于解决两个已有接口之间不匹配的问题,将一个接口使用到另一个已经确定的接口里面。解决两个不兼容的类同时工作。
bridge用于将接口和他的实现部分进行桥接,bridge必须知道一个抽象接口将有多个实现,并且接口和实现之间是独立演化的。 他和adapter使用场景不同。
facade是另外一组对象的adapter吗?不全是,他定义了全新的接口,而adapter遵从已有的接口,adapter是两个接口协调工作,所以叫适配器。
decorator和composite都有组合的能力,但是目的不同。 decorator用于给对象添加职责,composite用于
将多个对象以统一的方式处理、多个对象可以被当作一个对象来处理。
decorator重点在修饰,composite重在表示。
proxy与decorator写法有相似的地方,但是proxy不能动态的为对象添加性质。
decorator是动态的为对象添加功能。 而proxy只是控制对对象的访问,功能完全是由实际对象提供的。
应用: 一个通用的接口,希望使用一个已有的类。
原理:定义一个抽象的接口(或者目标类),总之是应用程序使用的类。这个类定义应用程序使用功能的接口原型。
但是目标类并不具备某些功能,而需要使用已有的另一个类。
这时可以有两种方法:
a 定一个类公有继承自目标类,同时私有继承自一个adaptee(提供功能的类)。在这个类里面使用已有类的功能。 多重类继承方式。
b 定一个类继承自目标类,同时引用一个已有类的实例。 对象组合方式。
2. ★ bridge 桥接
挺有用的一个模式。
应用:如果一个类定义了抽象接口,并且可以派生出子类来实现。 而这些子类的实现过程,又是希望可变化(比如在不同平台上实现)。
原理:一个抽象的类定义应用程序的接口。抽象类中持有一个imp类的引用,具体类中通过函数(用工厂方法)获取这个引用,并
使用这个引用提供的方法。
从实现过程可以看出,bridge是在对抽象接口的实现过程时,又做了一次抽象,来达到具体类的实现过程可变。
_imp像桥一样连接了应用抽象接口的实现 和 具体的实现过程。
手法就是一个组合,或委托。
实现:
class Window{
virtual void DrawContents();
protected:
WindowImp * GetWindowImp();
private:
WindowImp * _imp;
} ;
WindowImp * Window::GetWindowImp()
{
return Factory.Instance().MakeWindowImp(); ///////////在这里根据条件判断跨windows平台。
}
class IconWindow: Window
{
void DrawContents()
{
_imp = GetWindowImp();
_imp->DeviceRect();
}
};
class WindowImp{
virtual void DeviceRect() = 0;
};
class XWindowImp : public WindowImp
{
void DeviceRect()
{
xxxxxxxxxxxxxxx;
}
};
class PMWindowImp : public WindowImp
{
void DeviceRect()
{
xxxxxxxxxxxxxxx;
}
};
3. composite 组合
4. decorator 装饰(包装机)
应用: 以动态、透明的方式给一个对象添加职责
当不方便用继承的方式进行功能扩充时。例如有大量独立的扩展,每一种组合将产生大量的子类。
原理:为实际对象增加一个外壳,在外壳里面添加需要扩展的功能。
外壳与实际对象需要使用一个相同的对外接口,使得应用程序看不到外壳的存在。
所以,外壳是继承自一个抽象接口的,实际对象也继承自同一抽象接口。
由于外壳里面持有的实际对象可以在运行时刻变化,使得外壳(包装)与实际对象之间的交叉组合成为可能。
实现:
class VisualComponent{
virtual void Draw();
};
class Decorator: public VisualComponent ///////定义包装机的接口。并将被包装的具体对象引用放到了这里。
{
Decorator(VisualComponent * c):_component(c){}
virtual void Draw()
{
c->Draw();
}
private:
VisualComponent * _component;
};
class ConceretComponent : public VisualComponent/////////// 具体的对象
{
void Draw()
{
XXXXXX;
}
};
class ConceretDecorator:public Decorator /////////// 为对象增加的外壳之一。
{
void Draw()
{
xxxxxxxxx do some thing for conceret decorator;
Decorator::Draw();
}
};
////////////应用程序:
c = new ConceretDecorator(new ConceretComponent) ///// 这样就可以实现外壳与被包装之间的组合。可以避免以继承的方式进行静态扩展,带来的子类泛滥。
c->Draw();
相关模式: 适配器是希望利用现有对象,达到通用接口希望的功能,即把现有对象转化成另一个接口。
装饰是希望改变对象的职责,不改变他的接口。装饰使用对象的出发点还是现有对象,只在上面加一点附加(修饰)功能。
在实现手法上,装饰与桥接有点相似。他们的不同在于桥接的imp类的接口可以完全与具体类(应用程序调用的)接口不同。
桥接的本质是经过一次组合(或委托),将抽象接口的实现过程中可能出现的变化抽象到一个抽象接口上面去。
装饰则是两个类(已有对象与包装)都有各自的功能,应用程序希望在已有对象上面增加一定职责,并且希望灵活变化(如果固定的使用一个继承就完成扩展了)。
装饰的本质是在已有对象外面报个壳子(实现一些功能),把壳子交给应用程序使用,并且使应用程序认为这就是自己。在壳子的实现里面将功能再委托给已有对象。
通过可以灵活的更换壳子和已有对象的组合,达到扩展。
5. facade 外观
原理: 他为一个子系统、或一个提供功能的代码库设计一个应对一般情况的简化接口,使得应用程序不用看到子系统的全部细节接口。当然,如果应用
程序有更个性化的需求希望看到子系统内部接口,依旧允许看到。
他的好处是对应用程序屏蔽了复杂子系统内部庞杂的类、以及他们的互相配合关系,使得子系统的演化不影响应用程序。
他的应用是对一个庞大的库进行针对某些特定功能的封装,提供出接口。
实现:
class Scanner{
void Scan();
};
class Parser{
void Parse();
};
class Compiler{ //////////////这是一个facade。 他把编译子系统里面的部件集成到一起。提供一个简单的接口compile供应用程序使用。
void compile()
{
Scaner scan;
Parser parser;
scan.Scan();
parser.Parse();
xxxxxxxxxxxxxxx;
}
};
6. flyweight 享元
应用: 对那些通常因为数量太大而难以用对象来表示的概念或实体进行建模。
由于面向对象的编程所有东西都是对象,因此可能系统中需要创建大量的对象。比如:文档中的每一个字是一个对象。
使用条件:
一个应用程序使用了大量的对象
对象的大多数状态都可以变为外部状态
如果删除对象的外部状态,可以用相对较少的共享对象取代很多组对象
应用程序不依赖于对象标识。
原理: 区分出对象的内部状态和外部状态。 内部状态是可共享的,外部状态是可变的。
因内部状态可共享的特点,可以将很多对象用较少的共享对象来表示,在使用时临时增加响应的外部状态。
应用程序维持一个对flyweight的引用,同时计算或存储flyweight的外部状态。
flyweight通常与工厂方法一起使用,通过工厂维护较少量、可共享的flyweight对象。
实现:
class FlyWeight{
virtual void Operation(const string& extrinsicState);
void DosthforintrinsicState()
{
cout<<_intrinsicState<<endl;
}
protected:
FlyWeight(string intrinsicState):_intrinsicState(intrinsicState){}
private:
string _intrinsicState;
};
class ConceretFlyWeight : public FlyWeight
{
ConceretFlyWeight(string intrinsicState):FlyWeight(intrinsicState){}
void Operation(const string& extrinsicState)
{
this->DosthforintrinsicState(); /////////共享的内部状态
dosthforextrinsicState(extrinsicState); /////////可变的外部状态
}
}
class UnSharedFlyWeight: FlyWeight
{
void Operation(const string& extrinsicState)
{
doXXX(extrinsicState);
}
};
class FlyWeightFactory
{
FlyWeight * getFlyWeight(string key)
{
if(_exist(key))
{
return existing flyweight;
}
else
{
new FlyWeight(key);
add FlyWeight to pool of flyweights;
return the new flyweight;
}
}
};
app:
{
define a extrinsicState;
FlyWeight * fly = FlyWeightFactory::getFlyWeight(key);
fly.Operation(extrinsicState);
}
7. proxy 代理
原理: 代理对象持有一个实际对象的引用(这种方法和decorator类似)或持有一个可创建实际对象的标识,在代理对象实例化
的时候并不创建实际对象,等到使用的时候再创建。(virtual proxy模型)
或需要访问远程(或另一地址空间)的变量时(remote proxy模型)
或打算在访问实际对象时做一点事情(protection proxy模型),比如判断是否具有权限。这个模型写法类似decorator。
应用:当对象很大,不想在初始化的时候就创建所有对象,希望使用时再创建。
实现:
class Graphic
{
virtual void Draw() = 0; //////
};
class Image:public Graphic /////实际执行动作的类
{
void Draw()
{
xxxx;
实际的执行动作;
}
};
class proxy:public Graphic ////virtual proxy 代理,负责在需要创建实际对象时再创建
proxy(string filename):_filename(filename),_image(0){}
void Draw()
{
getImage()->Draw();
}
Image * getImage()
{
if(_image == 0)
{
_image = new Image(_filename);
}
}
private:
string _filename;
Image * _image;
};
class ProtectionProxy ////////Protection Proxy形式的proxy.
{
if(msg is legal)
{
getImage()->dothings();
}
else
{
getImage( doesnotunderstand_msg);
或者直接返回false;
cout<<"msg is error<<endl;
return false;
}
};
总结:adapter用于解决两个已有接口之间不匹配的问题,将一个接口使用到另一个已经确定的接口里面。解决两个不兼容的类同时工作。
bridge用于将接口和他的实现部分进行桥接,bridge必须知道一个抽象接口将有多个实现,并且接口和实现之间是独立演化的。 他和adapter使用场景不同。
facade是另外一组对象的adapter吗?不全是,他定义了全新的接口,而adapter遵从已有的接口,adapter是两个接口协调工作,所以叫适配器。
decorator和composite都有组合的能力,但是目的不同。 decorator用于给对象添加职责,composite用于
将多个对象以统一的方式处理、多个对象可以被当作一个对象来处理。
decorator重点在修饰,composite重在表示。
proxy与decorator写法有相似的地方,但是proxy不能动态的为对象添加性质。
decorator是动态的为对象添加功能。 而proxy只是控制对对象的访问,功能完全是由实际对象提供的。
相关文章推荐
- hdu 1307 N-Credible Mazes
- 随记(一)
- 五、Hive-HBase接口表性能分析
- Progress笔记
- 让表格的单元格不被选中的方法
- SQLite Expert Professional 为 主键无法设置自增长
- HBASE遇到的java.lang.OutOfMemoryError: unable to create new native thread解决方法
- 建立三个线程,A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC
- 讨论归讨论
- Linux内核学习笔记七——内核同步机制和实现方式
- 在Eclipse中使用JUnit4进行单元测试(初级篇)
- BZOJ4520: [Cqoi2016]K远点对
- Httplib模块使用
- GPU Shader 程序调试方法
- Linux的链接文件实用举例
- NATS学习 -- 概念学习之消息(Message)与发布订阅(Publish Subscribe)
- CloudFoundry in 1 Box简介:PCF-Dev篇
- 注册表开启启动项
- 设计模式简要总结——创建型模式
- nsstring 编码encode类型