您的位置:首页 > 编程语言 > C#

C#面向对象设计模式纵横谈 学习笔记7 Adapter适配器(结构型模式)

2008-01-08 01:24 519 查看
.从现实生活上来说,适配器可以想象为三相插头和二相插头的转换接头。那么适配的定义就是在不改变原有实现的基础上,将原先不兼容的接口转换为兼容的接口。

适配器模式的动机

在软件系统中,由于应用环境的变化,常常需要将"一些现存的对象"放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。如何应对这种"迁移的变化"?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?

适配器模式的意图

将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

现在看看适配器模式的代码。

现在有一个IStack的接口,定义了一个堆栈的接口


public interface IStack




...{


void Push(object item);




object Pop();




object Peek();


}

那么现在有一个对象适配器,它的主要特点是,被适配的类作为适配器的一个内部成员


//对象适配器


public class Stack : IStack//适配对象




...{




ArrayList list;//被适配的对象




public Stack()




...{


list = new ArrayList();


}






IStack 成员#region IStack 成员




public void Push(object item)




...{


list.Add(item);


}




public object Pop()




...{


object obj = list[list.Count - 1];


list.RemoveAt(list.Count - 1);


return obj;


}




public object Peek()




...{


return list[list.Count - 1];


}




#endregion


}



下面是一个类适配器,它的特点是适配器继承与被适配对象


//类适配器


public class CStack : ArrayList, IStack




...{






IStack 成员#region IStack 成员




public void Push(object item)




...{


this.Add(item);


}




public object Pop()




...{


object obj = this[this.Count - 1];


this.RemoveAt(this.Count - 1);


return obj;


}




public object Peek()




...{


return this[this.Count - 1];


}




#endregion


}

那么我们这两个堆栈类都是为了利用ArrayList类,让ArrayList实现一个堆栈的数据结构。他们都转换了ArrayList的用途。但是我们看看类适配器有2个缺点

在C#中,我们无法使用Private或Protected继承,让ArrayList的公开方法在派生类不暴露出来。在C#中,所有的继承都是公开继承,那么ArrayList的公开方法都可以被派生类生成的对象使用,那么这样破坏了封装性。

类适配器只能实现一个适配器对一个被适配对象,这个被适配对象是this。当我们的需求需要一个类适配器对应多个被适配对象,那么类适配器满足不了这个要求。

所以我们在适配器模式中推荐使用类适配器模式

Adapter模式的几个要点

Adapter模式主要应用于"希望复用一些现存的类,但是接口又与复用环境要求不一致的情况" ,在遗留代码复用、类库迁移等方面非常有用。

GoF 23 定义了两种Adapter模式的实现结构:对象适配器和类适配器。但类适配器采用"多继承"的实现方式,带来了不良的高耦合,所以一般不推荐使用。对象适配器采用
"对象组合"的方式,更符合松耦合精神。

Adapter模式可以实现的非常灵活,不必拘泥于Gof23中定义的两种结构。例如,完全可以将Adapter模式中的"现存对象"作为新的接口方法参数,来达到适配的目的。

Adapter模式本身要求我们尽可能地使用"面向接口的编程"风格,这样才能在后期很方便地适配。

在我们刚才代码中,我们定义了IStack接口,那么我们在使用Stack对象的时候,可以使用IStack接口来定义变量,这样让代码之间松耦合。

那么我们在.net中经常看到有一种adapter是作为参数来传递的如


DataSet ds = new DataSet();


SqlDataAdapter da = new SqlDataAdapter();


da.SelectCommand = "...";


da.Fill(ds);

那么这一是一种适配器模式,因为我们是在方法中,将数据由数据库源通过Adapter转换成DataSet对象,那么我们可以根据适配器的定义将一个类的接口转换成客户希望的另一个接口,我们现在将一个类的接口(数据库数据),转换成客户希望的另一个接口(DataSet即XML数据),SqlDataAdapter作为适配器,在Fill方法中将数据进行转换。

在.net中还有一种Adapter的变体IComparable接口。

实现一个排序适配器(继承IComparer接口),然后在其Compare 方法中对两个对象进行比较。

那么这里是使用一个方法作为适配器,将两个对象转换为对比后的bool值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐