我正在研究"设计模式解释"中的桥模式示例。我正在查看的示例是示例 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 Circle
和abstract Shape
<---
concrete Rectangle
,每次添加新框架以及每次现有框架中发生更改时,都必须重新编译和重新部署Circle
和Rectangle
。此类更改甚至可能涉及修改这些类的构造函数,因此模块的用户还必须更改其代码。
示例:您有一个模块的工作第一个版本,具有以下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
- 每个都针对你的模块支持的不同平台(所以,CircleImplGDI
,CircleImplTk
,CircleImplOpenGL
等)。
在ShapeFactory
的实现中,您将适当地创建一个特定的CircleImpl
,并且模块的客户端不必知道有关它的任何信息。此示例是您提供链接的示例的简化版本。请注意,现在,当使用其中一个可能的CircleImpl
s作为Circle
时,没有抽象类被实例化,因此这也应该清除有关抽象派生类的问题。
这种模式背后的主要思想是有两个抽象层次:Shape
是一个抽象的几何概念,Circle
和Rectangle
比Shape
更具体,但在绘制它们的许多技术可能性的背景下,它们仍然是相当抽象的。当您知道上下文时,存在特定形状的具体表示形式:例如 - 在光栅上绘制或使用矢量图形。
另一个抽象级别使你可以推迟更多关于代码的决定 - 首先,我们推迟决定我们拥有什么形状。然后,有了Circle
和Rectangle
,我们推迟了关于如何绘制它们的决定。延迟决策为我们提供了解耦的灵活代码(如"添加的 DPI"示例所示)。
任何类都允许使用纯虚拟方法,只要您不尝试创建该类的实例。