(一)适配器(Adapater)模式
适配器(Adapater)模式已经在10.4 串口通信与设计模式中进行了讲解。在此不在对它进行讲解。http://www.cnblogs.com/kid-li/archive/2006/05/29/412180.html
Adapter适配器模式是一种结构型模式,主要应对:由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是,新环境要求的接口是现存对象所不满足的。
《设计模式》中说道:将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的类可以一起工作。
在实际的生活中有很多例子,如:我们常使用的移动硬盘,无论是笔记本硬盘还是台式机硬盘,对于数据的传输都不使用Usb的数据线,外接的硬盘盒就是将原来的硬盘数据传输方式适合Usb数据线。(哎,我那个硬盘盒买的时候还190元,其实一点都不值,整个一个盒,就那个转接芯片比较值钱,我说50,人家不卖)。
我再接着说适配器模式,先举个简单的代码例子,我现在要做一个队列的类,实现先进先出的功能。利用ArrayList对象。
首先,我们先定义一些队列的接口,接口中定义队列的方法,代码如下:
interface IQueue
{
void push(object item); //进队列
object putout(); //出队列
objectShowLastItem(); //返回队列中最后一项
objectShowFirstItem(); //返回队列中第一项
}
下面我们再来利用ArrayList对象实现一个队列:
class Queue:IQueue
{
ArrayListadaptee;
public Queue()
{
adaptee= new ArrayList();
}
publicvoid push(object item)
{
adaptee.Add(item);
}
publicobject putout()
{
object item =adaptee[0];
adaptee.RemoveAt(0);
return item;
}
publicobject ShowLastItem()
{
returnadaptee[adaptee.Count-1];
}
publicobjectShowFirstItem()
{
return adaptee[0];
}
}
实现有了,现在用客户端程序调用来看一下结果:
class Class1
{
///<summary>
///应用程序的主入口点。
///</summary>
[STAThread]
staticvoid Main(string[] args)
{
Queuequeue = new Queue();
queue.push(1);
queue.push(2);
queue.push(3);
queue.push(4);
queue.push(5);
Console.Write("FirstItem:" + queue.ShowFirstItem().ToString() + "\n");
Console.Write("LastItem:" + queue.ShowLastItem().ToString() + "\n");
Console.Write("output:" + queue.putout().ToString() + "\n");
queue.push(6);
Console.Write("FirstItem:" + queue.ShowFirstItem().ToString() + "\n");
Console.Write("LastItem:" + queue.ShowLastItem().ToString() + "\n");
Console.Read();
}
}
输出结果:
FirstItem:1
LastItem:5
output:1
FirstItem:2
LastItem:6
(二)Bridge模式
Bridge桥接模式是一种结构型模式,它主要应对的是:由于类型的固有罗辑,使得类型具有两个或两个以上的纬度变化。也就是要求抽象不应依赖于实现细节,实现细节应依赖于抽象。
《设计模式》中说到将抽象部分与实现部分分离,使他们可以独立的变化。
举个例子更清楚些,好像我们平时玩的游戏中有PS版的,但是不是大家都有PS。这时我们等一段时间,一般会出PC版的或其他版本。由于支持游戏的平台不一样,但是如果我们编写的游戏程序为了适应另一种平台就要全部重新编写的话岂不是很麻烦。再加上游戏本身的变动,一句众人皆知的话:“死定了”。
实际上,我们要做到的是把变化的部分提出,对其抽象,使变化独立。那我们如何做呢?通过组合的方式将变化独立出去。将一个事物中的多个纬度变化分离。
下面举一个场景来理解一下,还是用汽车举例,我现在要一辆车(BMW或BORA)在路(WaterRoad或Cement)上跑。现在有两个纬度的变化点:汽车和路。也就是上图中的AbstractChangePoint1和AbstractChangePoint2。AbstractChangePoint1中包含有AbstractChangePoint2对象成员。。代码实现如下:
abstractclassAbstractCar
{
publicAbstractRoad road;
public AbstractCar(AbstractRoad road)
{
this.road = road;
}
publicabstractstring Run();
publicabstractstring Stop();
}
abstractclassAbstractRoad
{
publicabstractstring GetRoadType();
}
以汽车为变化中心,用组装的方式将两个变化点结合起来。使路的变化和汽车隔离。下面来编写路的实现。
classWaterRoad:AbstractRoad
{
publicoverridestring GetRoadType()
{
return"It isWaterRoad";
}
}
classCementRoad:AbstractRoad
{
publicoverridestring GetRoadType()
{
return"It is Cement";
}
}
然后再来编写汽车的实现
classBMWCar:AbstractCar
{
public BMWCar(AbstractRoad road)
: base(road)
{
}
publicoverridestring Run()
{
return"BMW isrunning";
}
publicoverridestring Stop()
{
return"BMW isstopped";
}
}
classBROACar:AbstractCar
{
public BROACar(AbstractRoad road)
: base(road)
{
}
publicoverridestring Run()
{
return"BROA isrunning";
}
publicoverridestring Stop()
{
return"BROA isstopped";
}
}
然后我们在客户代码中调用这些类,首先,我想要这个场景是BMW在WaterRoad上跑,客户端代码如下:
staticvoid Main(string[] args)
{
AbstractCar car = newBMWCar(newWaterRoad());
Console.WriteLine(car.road.GetRoadType());
Console.WriteLine(car.Run());
Console.WriteLine(car.Stop());
Console.Read();
}
实现结果如下:
It is WaterRoad
BMW is running
BMW is stopped
如果我现在要一辆BORA在Cement上跑,我们只要稍微修改一下car的实例化就可以,代码如下:
staticvoid Main(string[] args)
{
AbstractCar car = newBROACar(newCementRoad());
Console.WriteLine(car.road.GetRoadType());
Console.WriteLine(car.Run());
Console.WriteLine(car.Stop());
Console.Read();
}
实现结果如下:
It is Cement
BROA is running
BROA is stopped
最后我们再来说说Bridge模式的要点:
1、Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的纬度来变化。
2、所谓抽象和实现沿着各自纬度的变化,即“子类化”它们,得到各个子类之后,便可以任意组合它们。
3、Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决方法。
4、Bridge模式的应用一般在“两个非常强的变化纬度”,有时候即使有两个变化的纬度,但是某个方向的变化纬度并不剧烈——换言之两个变化不会导致纵横交错的结果,并不一定要使用Bridge模式。