假设我有一个类的层次结构,让我们使用经典的Shape
示例:
abstract class Shape
Circle : Shape
Square : Shape
我有第二层渲染器类,它以不同的方式处理形状的渲染:
abstract class ShapeRenderer
HtmlShapeRenderer : ShapeRenderer
WindowsFormsShapeRenderer : ShapeRenderer
允许这些独立变化传统上涉及使用Bridge模式。允许在不修改Shape
类的情况下扩展渲染操作传统上将涉及访问者模式。
然而,这两个都专注于扩展实现方而不是抽象方。说我想添加一个新的Shape
,比如说Triangle
- 我希望能够支持渲染Triangle
。由于Visitor和Bridge模式都依赖于将抽象层次“扁平化”为一组方法,例如:
public abstract class ShapeRenderer
{
public abstract void RenderCircle(Circle c);
public abstract void RenderSquare(Square s);
}
扩展Shape
层次结构的唯一方法是修改基类ShapeRenderer
类的代码,这是一个重大变化。
Jon,澄清一下:使用Bridge或Visitor允许客户端提供替代的渲染实现,但要求他们了解所有潜在的Shapes。我希望能够做的是允许客户 能够扩展Shape
类和要求它们为他们提供渲染实现新课。这样,现有代码可以使用任何类型的Shape
,而无需担心渲染它们的细节。
C#中可以使用这种问题的常见解决方案吗?
答案 0 :(得分:2)
我认为应该是一个突破性的变化。如果添加形状,现有的渲染器显然无法应对 - 它们需要更改。
您可以更改ShapeRenderer以将RenderTriangle()添加为虚拟(非抽象)方法,该方法仅记录无法正确渲染的事实,然后一次修复一个渲染器,但从根本上说,您是没有更多代码就无法呈现新类型。
你真的希望实现什么样的非破坏性改变?
答案 1 :(得分:2)
strategy pattern怎么样?策略是RenderEngine实现的引用。当您想要添加新形状时,您可以创建渲染引擎的新实现,该实现了解新的Shape实现并实现相应的渲染功能。您向Shape添加一个虚函数,它作为辅助函数来选择正确的形状渲染函数 - 即Circle对象调用renderCircle()函数等。
在C ++中可能看起来像:
class Triangle : public Shape
{
public:
Triangle( const RenderEngine& whichRenderEngine );
void render( void ) { renderStrategy->renderTriangle( *this );
private:
RenderEngine* renderStrategy;
};
class TriangleRender : HTMLShapeRender
{
public:
// if inheriting from concrete class, all other rendering functions
// already exist... otherwise re-implement them here.
void renderTriangle( const Triangle& t ) { /* impl */ }
};
HTMLRenderer r; // doesn't know about Triangles.
Circle c( &r );
c.render();
Square s( &r );
s.render();
// Now we add Triangle
TriangleRenderer tr;
Triangle t( &tr );
t.render();
Square s2( &tr ); // tr still knows how to render squares...
s2.render();
答案 2 :(得分:1)
设计接口而不是实现。
嘿 - 我今天两次使用相同的答案(我想Renderer是一个实现是有争议的)...我不确定我会选择ShapeRenderer类。那么由形状类实现的IRenderHTML,IRenderWindows呢?
您可以使用“形状”和“渲染”获得可扩展性。
我认为,将自己的圈子传递给实用程序类进行渲染可能会更好。您可以通过让形状自己进行渲染来轻松添加新形状和新渲染。
答案 3 :(得分:1)
我的解决方案几乎肯定是使用抽象工厂,在这种情况下我会加载一个按类型键入的ShapeRenderers字典,其中type是Shape的子类,让工厂提供每个所需的ShapeRenderer形状(可能是平台,例如Window,Web,iPhone)。
这样做意味着添加新形状只需要更改配置存储,以便工厂知道要映射哪些渲染器以及包含具体实现的新程序集。