结构型模式--桥接

1、意图

  将抽象部分与它的实现部分分离,使它们都可以独立地变化。

2、结构

 

 3、参与者

  Abstraction:定义抽象类的接口,维护一个指向Implementor类型对象的指针;

  RefinedAbstraction:扩充由Abstraction定义的接口;

  Implementor:定义实现类的接口,该接口不一定要与Abstraction的接口完全一致;事实上这两个接口可以完全不同。一般来讲,Implementor接口仅提供基本操作,而Abstraction则定义了基于这些基本操作的较高层次的操作;

  ConcreteImplementor:实现Implementor接口并定义它的具体实现;

4、适用性

  以下情况可以使用Bridge模式:

  当不希望在抽象和它的实现部分直接有一个固定的绑定关系(继承)。例如这种情况可能是因为在程序运行时刻实现部分应可以被选择或者切换;

  类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这是桥接模式使可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充;

  对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译;

  当希望对客户完全隐藏抽象的实现部分。在C++中,类的表示在类接口中是可见的;

  当希望在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。  

5、代码示例

// Window类为客户应用程序定义了窗口抽象类
class Window 
{
public:
    Window(view* contents);
    // requests handled by window 
    virtual void Drawcontents();
    virtual void open();
    virtual void close();
    virtual void Iconify();
    virtual void Deiconify();
    // requests forwarded to implementation 
    virtual void Setorigin(const Point& at);
    virtual void SetExtent(const Point& extent);
    virtual void Raise();
    virtual void Lower();
    virtual void DrawLine(const Point&,const Point&);
    virtual void DrawRect(const Point&,const Point&);
    virtual void DrawPolygon(const Point[],int n);
    virtual void DrawText(const char*,const Point&);
protected:
    windowImp* GetwindowImp(); 
    view* Getview ();
private:
    // Window维护一个对WindowImp的指针
    windowImp* _imp;
    view* _contents; // the window's contents
};
// WindowImp抽象类定义了一个对底层窗口系统的接口。
class WindowImp
{
public:
    virtual void ImpTop()= 0; 
    virtual void ImpBottom()= 0;
    virtual void ImpSetExtent(const Point&)= 0;
    virtual void ImpSetorigin(const Point&)= 0;
    virtual void DeviceRect(Coord,Coord,Coord,Coord)= 0;
    virtual void DeviceText(const char*,Coord,Coord)= 0;
    virtual void DeviceBitmap(const char*,Coord,Coord)= 0;
    // lots more functions for drawing on windows...
protected:
    WindowImp();
};
// Window的子类定义了应用程序可能用到的不同类型的窗口,如应用窗口、图标、对话框临时窗口以及工具箱的移动面板等等。
// 例如ApplicationWindow类将实现DrawContents操作以绘制它所存储的View实例
class Applicationwindow : public Window
{
public:
    virtual void DrawContents();
};
void Applicationwindow::DrawContents ()
{
    Getview()->DrawOn(this);
}

// IconWindow中存储了它所显示的图标对应的位图名…
class IconWindow : public Window 
{
public:
    // ...
    virtual void DrawContents();
private:
    const char* _bitmapName;
};

// ...并且实现DrawContents操作将这个位图绘制在窗口上:
void IconWindow::DrawContents() 
{
    WindowImp* imp = GetwindowImp();
    if(imp != 0)
    {
        imp->DeviceBitmap(_bitmapName, 0.0, 0.0);
    }
}

// Window的操作由WindowImpl的接口定义。例如,在调用WindowImp操作在窗口中绘制矩形之前,DrawRect必须从它的两个Point参数中提取四个坐标值:
void Window::DrawRect (const Point& pl,const Point& p2)
{
    WindowImp* imp = GetwindowImp();
    imp->DeviceRect (p1.X(),p1.Y(),p2.X(),p2.Y());
}
// 具体的WindowImp子类可支持不同的窗口系统,XwindowImp子类支持X Window窗口系统:
class XWindowImp : public WindowImp
{
public:
    XWindowImp();
    virtual void DeviceRect(Coord,Coord,Coord,Coord);
    // remainder of public interface...
private:
    // lots of X window system-specific state,including:
    Display* _dpy;
    Drawable _winid;// window id 
    GC _gc;    // window graphic context
};
// 对于Presentation Manager(PM),我们定义PMWindowImp类:
class PMWindowImp : public WindowImp
{
public:
    PMWindowImp ();
    virtual void DeviceRect(Coord,Coord,Coord,Coord);
    // remainder of public interface...
private:
    // lots of PM window system-specific state,including:
    HPS hps;
};

// 这些子类用窗口系统的基本操作实现WindowImp操作,例如,对于X窗口系统这样实现DeviceRect:
void XWindowImp::DeviceRect( Coord x0,Coord yo,Coord x1,Coord y1)
{
    int x = round(min(x0,x1));
    int y = round(min(y0,y1));
    int w = round(abs(x0 - x1));
    int h = round(abs(yo - y1));
    XDrawRectangle(_dpy,_winid,_gc,x,y,w,h);
}
// PM的实现部分可能象下面这样:
void PMWindowImp::DeviceRect(Coord x0,Coord yo,Coord x1,Coord y1)
{
    Coord left min(x0,x1);
    Coord right max(x0,x1);
    Coord bottom min(yo,y1);
    Coord top max(y0,y1);

    PPOINTL point[4];
    point[0].x = left;
    point[0].y = top;
    point[1].x = right;
    point[1].y = top; 
    point[2].x = right; 
    point[2].y = bottom; 
    point[3].x = left;
    point[3].y = bottom;
    if((GpiBeginPath(_hps,1L)==false) ||
        (GpiSetCurrentPosition(_hps,&point [3])==false) ||
        (GpiPolyLine(_hps,4L,point)==GPI_ERROR) ||
        (GpiEndPath(_hps)==false))
    {
        // report error
    }
    e1se
    {
        GpistrokePath(_hps,1L,0L);
    }
}
// 取正确的WindowImp子类实例
// Window类的GetWindowImp操作负责从一个抽象工厂中得到正确的实例,这个抽象工厂封装了所有窗口系统的细节。
WindowImp* window::GetwindowImp ()
{
    if (_imp == 0)
    {
        _imp=WindowsystemFactory::Instance()->MakewindowImp();     
    }
    return_imp;
}

 6、总结

  桥接模式使得抽象和实现进行分离、解耦,抽象部分和实现部分可以独立变化。

  当一个抽象有多个实现时,如果用继承机制来协调,则抽象部分和实现部分固定在一起了,难以对抽象和实现部分独立地进行修改、扩充和重用,而桥接模式则避免了这种强耦合。

  抽象对外提供接口供用户调用,而实现部分对用户则不可见。

  抽象类维护实现类的引用(或指针)(通过对象组合方式),从而实现抽象类对实现类的调用。实现类可以有多个子类,抽象类根据多态机制切换不同实现类的调用。

  

posted @ 2022-05-02 19:07  流翎  阅读(25)  评论(0编辑  收藏  举报