前言
从字面意思上感觉代理、适配器、桥接、中介者有很大的共性。通过这样的对比学习让我们深入了解一下这四种模式吧。
代理模式
为其他对象提供一种代理以控制对这个对象的访问。用户不想或者不能直接引用一个对象,而代理对象可以在用户与对象之间起到中介的作用。例如桌面上的快捷方式则是应用程序的一个代理。下面是代理模式的结构图:
举个例子:拖朋友去国外买iPhone
创建抽象主题类:
创建具体主题类:
创建代理类:
客户端代码:
优点
- 降低了用户与对象直接的耦合度。
- 可以扩展具体的主题类或者主题类的功能,扩展性好。
缺点
- 由于增加了一个代理对象,导致请求速度变慢。
- 增加了系统的复杂性
适配器模式
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能在一起工作的那些类可以一起工作。下面为适配器模式的结构图:
举个栗子:我家电器插头是两头的,而插排都是三头的,我们现在希望把三头插头转换为两头插头。
创建一个需要适配的三头插头的类或接口:
创建一个用户期待的两头插头的类:
创建一个适配器类:
客户端代码:
优点
将目标类和适配器者类解耦,增加了类的复用性,在不修改原代码的基础上来复用现有类,符合开闭原则
缺点
一次最多只能适配一个适配者类,不能同时适配多个适配者。
桥接模式
将抽象部分与它的实现部分分离,使它们都可以独立地变化。下面为桥接模式的结构图:
举个栗子:电视都有遥控器,我们可以把遥控器当做一个抽象类,抽象类中提供遥控器所有功能的实现,当然其他的遥控器也继承这个抽象类。
创建抽象类或者接口、集体的实现类:电视类和集体的实现方法
public abstract class TV
{
public abstract void On();
public abstract void Off();
public abstract void Set();
}
public class Samsung : TV
{
public override void On()
{
Console.WriteLine("打开三星电视");
}
public override void Off()
{
Console.WriteLine("关闭三星电视");
}
public override void Set()
{
Console.WriteLine("更换三星电视频道");
}
}
public class SONY : TV
{
public override void On()
{
Console.WriteLine("打开索尼电视");
}
public override void Off()
{
Console.WriteLine("关闭索尼电视");
}
public override void Set()
{
Console.WriteLine("更换索尼电视频道");
}
}
创建抽象类、被提炼的抽象:遥控器及要扩充的功能
public class RemteControl //遥控器
{
private TV implementor;
public TV Implementor
{
get { return implementor; }
set { implementor = value; }
}
public virtual void On()
{
implementor.On();
}
public virtual void Off()
{
implementor.Off();
}
public virtual void Set()
{
implementor.Set();
}
}
//要扩充的新功能,重写了这个方法,注意base.set 很关键
public class ConcreteRemote : RemteControl
{
public override void Set()
{
base.Set();
Console.WriteLine("新功能");
}
}
客户端代码和结果:
优点
- 把抽象接口与其实现解耦。
- 抽象和实现可以独立扩展,不会影响到对方。扩展性极好
- 提高代码的复用性
缺点
- 增加了系统的复杂性,不容易区分,难维护。
中介者模式
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变他们之间的交互。下面是中介者模式的结构图:
举个栗子:租房,有租户、租主、中介
创建抽象的同事类、抽象中介者:
//抽象中介者
public abstract class MediatorQ
{
public abstract void Show(string Message, Colleague colleague);
}
//抽象同事类
public abstract class Colleague
{
protected MediatorQ Mediator;
public Colleague(MediatorQ Mediator)
{
this.Mediator = Mediator;
}
}
具体的同事类:租户和租主
//具体同事类:租户
class Tenant : Colleague
{
public Tenant(MediatorQ Mediator) : base(Mediator)
{
}
public void Show(string message)
{
Mediator.Show(message, this);
}
public void GetMessage(string message)
{
Console.WriteLine("租住信息:"+message);
}
}
//具体同事类:租主
class Landlord : Colleague
{
public Landlord(MediatorQ Mediator) : base(Mediator)
{
}
public void Show(string message)
{
Mediator.Show(message, this);
}
public void GetMessage(string message)
{
Console.WriteLine("租住信息:"+message);
}
}
具体的中介:
//具体中介者
class ConcreataMediator : MediatorQ
{
//获取租户和租主的消息,并赋值
private Tenant colleague1;
private Landlord colleague2;
public Tenant Colleague1
{
set { colleague1 = value; }
}
public Landlord Colleague2
{
set { colleague2 = value; }
}
//对抽象中介者方法进行声明,实现两个对象之间的通信
public override void Show(string message, Colleague colleague)
{
if (colleague==colleague1)
{
colleague2.GetMessage(message);
}
else
{
colleague1.GetMessage(message);
}
}
客户端代码:
static void Main(string[] args)
{
//实例一个具体的中介者
ConcreataMediator C = new ConcreataMediator();
//实例化具体租户c1和租主c2
Tenant c1 = new Tenant(C);
Landlord c2 = new Landlord(C);
//获得双方信息
C.Colleague1 = c1;
C.Colleague2 = c2;
c1.Show("我想住一个1000平米的房子");
c2.Show("我家房租符合您的要求");
Console.Read();
}
优点
- 减少对象之间直接交互所产生的错误,多个对象之间通过中介者来交互
- 同事之间解耦,提供系统的灵活性,使得各个同事对象独立而易于复用
缺点
- 中介者模式中,中介者角色承担了较多的责任,所以一旦这个中介者对象出现了问题,整个系统将会受到重大的影响
总结
虽然总结的时候会花很长时间,但是经过这样的一个过程之后,发现这四个模式之间并没有很大的共性,每个各有千秋,本来一个模式就是解决一个问题,谨慎使用!