我正在研究“设计模式解释”中的桥梁模式示例。 我正在看的例子是例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);
};
在Circle课程中我们有
#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
在继承类中是纯虚拟的,因为该方法实际上是在基类中实现的?
答案 0 :(得分:4)
想象一下,您正在构建一个模块,使用不同的API(Windows GDI,一些智能手机API,OpenGL,任何东西)绘制形状。拥有典型的层次结构abstract Shape
<---
concrete Circle
和abstract Shape
<---
concrete Rectangle
,您必须重新编译并重新部署Circle
和{{ 1}}每次添加新框架时,每次在现有框架中发生变化时。这些更改甚至可能涉及修改这些类的构造函数,因此模块的用户也必须更改其代码。
示例:您的模块有第一个版本,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(...);
};
),但它们会导致高度耦合且难以维护的代码。如果您使用桥接模式,您可以保持您的清晰设计完好无损并仍然表达您的域名(一般来说,“圈子”的概念不应该知道任何有关“dpi分辨率”的事情。)
所以:
CircleWithDpi
和
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
时,没有抽象类被实例化,所以这也应该清除你关于抽象派生类的问题。
这种模式背后的主要思想是有两个抽象层次:Circle
是一个抽象的几何概念,Shape
和Circle
比Rectangle
更具体但是在绘制它们的许多技术可能性的背景下,它们仍然是非常抽象的。当您知道上下文时,会存在特定形状的具体表示:例如 - 在栅格上绘图或使用矢量图形。
另一个抽象层次使您可以推迟更多关于代码的决策 - 首先我们推迟决定我们的形状。然后,Shape
和Circle
我们推迟了如何绘制它们的决定。延期决策为我们提供了解耦的,灵活的代码(如“添加的DPI”示例所示)。
答案 1 :(得分:1)
只要您不尝试创建该类的实例,就可以在任何类中使用纯虚方法。