我们以日志记录为例,来说明此模式的应用,先看下面的基本代码:
public abstract class Log
{
public abstract void Write(string msg);
}

public class DataBaseLog:Log
{
public override void Write(string msg)
{
}
}

public class FileLog:Log
{
public override void Write(string msg)
{
}
}
从代码,我们知道,有两种记录日志的方式:一种是数据库相关的,一种是跟文件相关的,我们进行了抽象,然后用两个字类来实现抽象;现在有这么一种情况:我们
是并没有考虑到平台的变化,默认认为是在同一平台上实现的;如果需求在平台上是有变化的,比如在.Net平台,JAVA平台,甚至可能是Borland平台,我们可能再继续继承下去,例如这样的代码:
public class NetDataBaseLog:DataBaseLog
{
public override void Write(string msg)
{
//.Net平台的数据库日志记录实现
}
}
public class JavaDataBaseLog:DataBaseLog
{
public override void Write(string msg)
{
//JAVA平台的数据库日志记录实现

}
}
public class OtherDataBaseLog:DataBaseLog
{
public override void Write(string msg)
{
//
其他某一平台的数据库日志记录实现
}
}
上面的代码我们只实现了数据库相关的不同平台的日志记录实现,文件相关的实现方式省略了;如果我们再引入一种新的平台,按这种思路,我们应该新增类,提示新平台下的两种记录方式的实现;如果我们在引入一种新的日志记录方式,我们同样要新增类,提供不同平台的实现;这些我们提供的这些类的实现中,必然存在重复的代码,如果变化在平台和实现两个两个方向上同时存在的话,必然导致类的迅速膨胀,导致类的层次过于复杂,这必然带来代码维护的成本。
我们说一个类应该只有一个引起它变化的因素,但是上面的代码显然违背这一单一职责原则,Log类现在的变化因素有两个,出于这个问题,我们需要使用桥接模式。
先看结构图:

我们先不必考虑这个模式具体的实现,先自己再来分析一下上面所碰到的问题如何处理。
我们现在可以肯定的是LOG这个抽象类应该可以定下来,将来的具体的实现只要继承实现就可以,这是一个方向的变化;我们也知道将来会发生平台上的变化;我们上面的代码是使用了继承的方式解决了变化的问题,但却带来了新的问题,继承使这两种变化的实现绞在了一起;既然平台会像实现方式那样激烈变化,那么我们当然可以像实现方式那样有如下的代码:
public abstract class ImpLog
{
public abstract void Execute(string msg);
}
public class NetImpLog:ImpLog
{
public override void Execute(string msg)
{
}
}
public class JavaImpLog:ImpLog
{
public override void Execute(string msg)
{
}
}
public class OtherImpLog:ImpLog
{
public override void Execute(string msg)
{
}
}
我们可以发现:记录方式的变化和平台的方向上的变化是一种平行关系,但是现在的问题是如何将这两者联系起来?我们可以使用对象组合的方式来解决:在我们的Log类里面,放一个ImpLog的字段,那么Log及其子类修改后如下:
public abstract class Log
{
protected ImpLog implementor;
public Log(ImpLog imptor)
{
this.implementor = imptor;
}
public ImpLog Implementor
{
get
{
return this.implementor;
}
set
{
this.implementor = value;
}
}
public abstract void Write(string msg);
}
public class DataBaseLog:Log
{
public DataBaseLog(ImpLog imp)
: base(imp)
{
//
.
}
public override void Write(string msg)
{
//
implementor.Execute();
//
}
}
public class FileLog:Log
{
public FileLog(ImpLog imp)
: base(imp)
{
//
.
}
public override void Write(string msg)
{
//
implementor.Execute();
//
}
}
public class OtherDataBaseLog:DataBaseLog
{
public OtherDataBaseLog(ImpLog imp)
: base(imp)
{
}
public override void Write(string msg)
{
//
其他某一平台的数据库日志记录实现

//
implementor.Execute();
//
}
}
我们通过对象组合的方式,在LOG类里面放置了平台基类的一个字段,在构造函数里面初始化它,并添加了它的属性,且可以让LOG子类继承到这个字段;这个其实就是我们的桥模式,通过对象的组合方式,将两个方向上的变化桥接在一起;下面是我们的客户调用代码:
static void Main(string[] args)
{
ImpLog impNet = new NetImpLog();
DataBaseLog logDb = new DataBaseLog(impNet);
logDb.Write("Net Database Log");

FileLog logFi = new FileLog(impNet);
logFi.Write("Net File Log");
logFi.Write();

ImpLog impJava = new JavaImpLog();
DataBaseLog logDb2 = new DataBaseLog(impJava);
logDb2.Write("Java Database Log");

FileLog logFi2 = new FileLog(impJava);
logFi2.Write("Java File Log");
}
可以看出,我们组合出了很多情况的日志记录实现,而不要添加那么多的类,这就是桥接模式所带来的便捷。
桥模式一个核心就是”多维度的非常强的变化“。如果其中一个变化并是剧烈,或者说两个变化并不会产生纵横交错的效果,那么并不适合使用这个模式。
桥模式类似于多继承,比如我们放置的平台基类的字段,这是不是有一种继承了平台类的味道?但是比真正的多继承有更多的优点,因为多继承往往带来的是违背单一职责的原则。
public abstract class Log
{
public abstract void Write(string msg);
}
public class DataBaseLog:Log
{
public override void Write(string msg)
{
}
}
public class FileLog:Log
{
public override void Write(string msg)
{
}
}是并没有考虑到平台的变化,默认认为是在同一平台上实现的;如果需求在平台上是有变化的,比如在.Net平台,JAVA平台,甚至可能是Borland平台,我们可能再继续继承下去,例如这样的代码:
public class NetDataBaseLog:DataBaseLog
{
public override void Write(string msg)
{
//.Net平台的数据库日志记录实现
}
}
public class JavaDataBaseLog:DataBaseLog
{
public override void Write(string msg)
{
//JAVA平台的数据库日志记录实现
}
}
public class OtherDataBaseLog:DataBaseLog
{
public override void Write(string msg)
{
//
其他某一平台的数据库日志记录实现
}
}我们说一个类应该只有一个引起它变化的因素,但是上面的代码显然违背这一单一职责原则,Log类现在的变化因素有两个,出于这个问题,我们需要使用桥接模式。
先看结构图:

我们先不必考虑这个模式具体的实现,先自己再来分析一下上面所碰到的问题如何处理。
我们现在可以肯定的是LOG这个抽象类应该可以定下来,将来的具体的实现只要继承实现就可以,这是一个方向的变化;我们也知道将来会发生平台上的变化;我们上面的代码是使用了继承的方式解决了变化的问题,但却带来了新的问题,继承使这两种变化的实现绞在了一起;既然平台会像实现方式那样激烈变化,那么我们当然可以像实现方式那样有如下的代码:
public abstract class ImpLog
{
public abstract void Execute(string msg);
}
public class NetImpLog:ImpLog
{
public override void Execute(string msg)
{
}
}
public class JavaImpLog:ImpLog
{
public override void Execute(string msg)
{
}
}
public class OtherImpLog:ImpLog
{
public override void Execute(string msg)
{
}
}
public abstract class Log
{
protected ImpLog implementor;
public Log(ImpLog imptor)
{
this.implementor = imptor;
}
public ImpLog Implementor
{
get
{
return this.implementor;
}
set
{
this.implementor = value;
}
}
public abstract void Write(string msg);
}
public class DataBaseLog:Log
{
public DataBaseLog(ImpLog imp)
: base(imp)
{
//
.
}
public override void Write(string msg)
{
//
implementor.Execute();
//
}
}
public class FileLog:Log
{
public FileLog(ImpLog imp)
: base(imp)
{
//
.
}
public override void Write(string msg)
{
//
implementor.Execute();
//
}
}
public class OtherDataBaseLog:DataBaseLog
{
public OtherDataBaseLog(ImpLog imp)
: base(imp)
{
}
public override void Write(string msg)
{
//
其他某一平台的数据库日志记录实现
//
implementor.Execute();
//
}
}
static void Main(string[] args)
{
ImpLog impNet = new NetImpLog();
DataBaseLog logDb = new DataBaseLog(impNet);
logDb.Write("Net Database Log");
FileLog logFi = new FileLog(impNet);
logFi.Write("Net File Log");
logFi.Write();
ImpLog impJava = new JavaImpLog();
DataBaseLog logDb2 = new DataBaseLog(impJava);
logDb2.Write("Java Database Log");
FileLog logFi2 = new FileLog(impJava);
logFi2.Write("Java File Log");
}桥模式一个核心就是”多维度的非常强的变化“。如果其中一个变化并是剧烈,或者说两个变化并不会产生纵横交错的效果,那么并不适合使用这个模式。
桥模式类似于多继承,比如我们放置的平台基类的字段,这是不是有一种继承了平台类的味道?但是比真正的多继承有更多的优点,因为多继承往往带来的是违背单一职责的原则。
浙公网安备 33010602011771号