场景
写日志功能
日志功能可能运行在不同操作系统上(Linux系统, Windows系统, Android系统, ios系统等),
日志有不同的格式(XML格式, TXT格式, SelfDefine格式)
这里明显有两个维度(操作系统和日志格式).
无论什么格式的日志, 在写入时, 需要调用不同系统的文件操作API.
所以日志格式在抽象维度, 操作系统在实现维度.
角色
Log 提供AddLog方法给其子类调用, 客户也可以使用该方法; Log::AddLog中调用对应的WriteString().
TXT, XML, SelfDefine:具体日志格式子类. 子类中需要调用Log::AddLog().
Writer: 抽象写入字符类, 提供WriterString接口给Log类使用.
LinuxWriter, WindowsWriter, AndroidWriter: 不同系统下写入字符的实现类.
Client不一定只对Log操作, 它也可以对TXT, XML, SelfDefine类操作, 根据需求而定.
如图:
图1
代码
class Log
{
...
void AddLog();
Writer* m_pWriter; // 聚合一个具体的Writer
};
// 这里忽略了参数
void Log::AddLog(...)
{
m_pWriter->WriteString(...); // 调用具体Writer的WriteString()函数
}
// Client使用
// 生成TXT日志, Window是下
TXT* pTXT = new TXT;
pTXT->m_pWriter = WindowsWriter();
pTXT->MakeTXTLog();
这里的代码主要表现桥模式中的抽象与实现分离, 这里在Client调用时, Client需要知道具体的Log和具体的Writer(Client负责生成这些对象). 如果想要Client与具体的Log类和具体的Writer类解耦, 可以使用相应的创建型模式来创建具体Log对象和具体Writer对象
//
我的理解
通过这个例子, 桥模式的特点很明显的表现了出来.
1. TXT, XML, SelfDefine与LinuxWriter, WindowsWriter, AndroidWriter被隔离开了; 通过Log和Writer隔开. Log和Writer就像一条桥梁起到通信的作用.
2. TXT, XML, SelfDefine与LinuxWriter, WindowsWriter, AndroidWriter之间的内部的变化互不影响.
Writer公开WriteString()接口给Log使用(类似一种回调), 通过WriteString()接口把Log与LinuxWriter, WindowsWriter, AndroidWriter解耦.
3. Log与是Writer一种聚合关系(整体与部分的关系), 不是一种组合关系.
4. TXT, XML, SelfDefine的各自函数中会使用其父类的Log::AddLog()函数, Log::AddLog()函数的实现中调用Writer::WriteString接口.
5. 在生成Log对象时, 需要根据需求生成LinuxWriter, WindowsWriter, AndroidWriter对象, 并由Log对象保存管理(LinuxWriter, WindowsWriter, AndroidWriter的创建你可以使用相关的创建型模式来创建).
6. Client完全可以不管TXT, XML, SelfDefine而直接生成Log对象来写入任意格式的日志, 而TXT, XML, SelfDefine就是定义了日志格式.
7. 日志格式和怎样写入就是这里的两个维度. 日志格式是抽象维度, 怎样写入是实现维度. 反过来行吗? 也可以吧, 但是有点不合理,
因为日志一运行就决定了其在什么系统上, 而格式可以随时变化. 如果反过来, 格式稳定, 随时在不同的系统上运行. 而且从结构图中可以看到LinuxWriter, WindowsWriter, AndroidWriter都有公共接口WriteString(), 而TXT, XML, SelfDefine就没有公共的接口.
如果一定这么做, 那就是这样子:
图2
不管怎么换, 实现维度必须有公共接口.
8. 这样的结构又是什么模式? 这样子是不是更灵活?
图3