"Designed Patterns Explained"中的桥接模式示例

Bridge pattern example from "Designed Patterns Explained"

本文关键字:模式 桥接 Designed Patterns Explained      更新时间:2023-10-16

我正在研究"设计模式解释"中的桥模式示例。我正在查看的示例是示例 10.3,可以在

http://www.netobjectives.com/resources/books/design-patterns-explained/cpp-code-examples/chapter10#10-3

我遇到的具体混淆是 Shape 类及其派生类。

#pragma once
#include "Drawing.h"
class Shape
{
public:
    Shape(Drawing *aDrawing);
    virtual void draw()= 0;
protected:
    Drawing *myDrawing;
    void drawLine( double, double, double, double);
    void drawCircle( double, double, double);
public:
    ~Shape(void);
};

在圆类中,我们有

#pragma once
#include "Shape.h"
class Circle : public Shape
{
public:
    Circle(Drawing*, double, double, double);
    virtual void draw();
    virtual void drawCircle(double, double, double)=0;
public:
    ~Circle(void);
protected:
    double _x, _y, _r;
};

所以我的问题是:为什么drawCircle继承的类中可以是纯虚拟的,因为该方法实际上是在基类中实现的?

想象一下,

你正在构建一个模块来使用不同的API(Windows GDI,一些智能手机API,OpenGL等)绘制形状。具有典型的层次结构abstract Shape <--- concrete Circleabstract Shape <--- concrete Rectangle,每次添加新框架以及每次现有框架中发生更改时,都必须重新编译和重新部署CircleRectangle。此类更改甚至可能涉及修改这些类的构造函数,因此模块的用户还必须更改其代码。

示例:您有一个模块的工作第一个版本,具有以下Circle接口:

class Circle : public Shape
{
  public:
    Circle(int x, int y, int radius);
    void draw(...);
};

然后,碰巧其中一个平台的优化原因迫使您提前了解当前平台的DPI分辨率(在实际绘制圆圈之前)。因此,您必须更改构造函数:

class Circle : public Shape
{
  public:
    Circle(int x, int y, int radius, int dpi);
    void draw(...);
};

代码的客户端将不得不重新编译其应用程序。当然,有一些黑客可以避免这种情况(比如引入CircleWithDpi),但它们会导致高度耦合且难以维护的代码。如果你使用桥接模式,你可以保持你的清晰设计不变,并且仍然表达你的领域(一般来说,"圆圈"的概念不应该知道任何叫做"dpi分辨率"的东西)。

所以有:

class Circle : public Shape
{
  public:
    Circle(int x, int y, int radius);
    virtual void draw(...) = 0;
};

class CircleImpl : public Circle
{
  public:
    CircleImpl(int x, int y, int radius, int dpi);
    //perform some calculations before drawing for optimization
    void draw(...);
    //draw using appropriate API
};

class ShapeFactory
{
  public:
    virtual Circle* CreateCircle(int x, int y, int radius) = 0;
};

当然,你会有很多CircleImpl - 每个都针对你的模块支持的不同平台(所以,CircleImplGDICircleImplTkCircleImplOpenGL等)。

ShapeFactory的实现中,您将适当地创建一个特定的CircleImpl,并且模块的客户端不必知道有关它的任何信息。此示例是您提供链接的示例的简化版本。请注意,现在,当使用其中一个可能的CircleImpl s作为Circle时,没有抽象类被实例化,因此这也应该清除有关抽象派生类的问题。

这种模式背后的主要思想是有两个抽象层次:Shape是一个抽象的几何概念,CircleRectangleShape更具体,但在绘制它们的许多技术可能性的背景下,它们仍然是相当抽象的。当您知道上下文时,存在特定形状的具体表示形式:例如 - 在光栅上绘制或使用矢量图形。

另一个抽象级别使你可以推迟更多关于代码的决定 - 首先,我们推迟决定我们拥有什么形状。然后,有了CircleRectangle,我们推迟了关于如何绘制它们的决定。延迟决策为我们提供了解耦的灵活代码(如"添加的 DPI"示例所示)。

任何类都允许使用纯虚拟方法,只要您不尝试创建该类的实例。