Estendendo ambos os lados de um visitante / padrão Bridge

votos
3

Digamos que eu tenha uma hierarquia de classes, vamos usar os clássicos Shapeexemplos:

abstract class Shape
Circle : Shape
Square : Shape

Tenho uma segunda hierarquia de classes renderizador que lidam com a prestação de formas de diferentes maneiras:

abstract class ShapeRenderer
HtmlShapeRenderer : ShapeRenderer
WindowsFormsShapeRenderer : ShapeRenderer

Permitindo que estas variam de forma independente que tradicionalmente envolvem usando o padrão Bridge. Permitindo que as ações de renderização para ser estendido sem modificar as Shapeaulas que tradicionalmente envolvem o padrão Visitor.

No entanto, ambos se concentrar exclusivamente sobre a extensão lado a implementação e não o lado da abstração. Digamos que eu queria adicionar um novo Shape, dizem Triangle- eu quero ser capaz de suportar tornando o Trianglebem. Uma vez que tanto o Visitante eo padrão Bridge dependem de achatamento da hierarquia de abstração em um conjunto de métodos, por ex:

public abstract class ShapeRenderer
{
     public abstract void RenderCircle(Circle c);
     public abstract void RenderSquare(Square s);
}

A única maneira de estender a Shapehierarquia é modificar o código da base de ShapeRendererclasse, que é uma alteração de quebra.

Jon, para esclarecer: Usando a Ponte ou visitante permite que os clientes para fornecer implementações de renderização alternativos, mas exige que eles sabem sobre todas as formas possíveis. O que eu gostaria de ser capaz de fazer é permitir que os clientes também ser capaz de estender a Shapeclasse e exigir -lhes para fornecer uma implementação de renderização para sua nova classe. Desta forma, o código existente pode trabalhar com qualquer tipo de Shape, sem se preocupar com os detalhes de torná-los.

Existe uma solução comum para este tipo de problema utilizável em C #?

Publicado 09/12/2008 em 18:00
fonte usuário
Em outras línguas...                            


4 respostas

votos
2

Eu acho que deve haver uma mudança de ruptura. Se você adicionar uma forma, os representantes existentes claramente não está indo para ser capaz de lidar - eles precisam ser alterados.

Você poderia mudar ShapeRenderer para adicionar RenderTriangle () como um método virtual (não-abstract), que apenas registra o fato de que ele não pode processar apropriadamente, e depois corrigir-se os representantes de um de cada vez, mas, fundamentalmente, você não está indo para ser capaz de tornar o novo tipo, sem mais código.

Que tipo de mudança não quebra você está realmente esperando para conseguir?

Respondeu 09/12/2008 em 18:17
fonte usuário

votos
1

Design para uma interface não uma implementação.

Hey - eu começar a usar a mesma resposta duas vezes hoje (i acho que é discutível que Renderer é uma implementação) ...

Eu não tenho certeza se eu iria com a classe ShapeRenderer. Que tal um IRenderHTML, IRenderWindows que são implementados pelas classes de forma?

Você começa a extensibilidade com as formas, bem como com as renderizações.

Eu acho que pode ser melhor OO dizer hey círculo ir tornar-se, do que passar o círculo para uma classe de utilitário para renderização. Você poderia facilmente adicionar novas formas e novas representações, deixando as formas que os próprios renderização.

Respondeu 09/12/2008 em 18:22
fonte usuário

votos
1

Minha solução aqui seria quase certamente ser a utilização de um Abstract Factory, caso em que eu carregar um dicionário de ShapeRenderers introduzidos por tipo, onde tipo é uma sub-classe de forma e deixar a fábrica fornecer a ShapeRenderer necessário para cada forma (e possivelmente plataforma, por exemplo. Janela, web, iPhone).

Fazendo dessa forma, significa que a adição de uma nova forma exigiria apenas uma mudança para uma loja de configuração, de modo a fábrica sabe o que renderizadores para mapear com o que molda, e um novo conjunto contendo as implementações concretas.

Respondeu 09/12/2008 em 18:58
fonte usuário

votos
2

Como sobre o padrão de estratégia ? Onde a estratégia é uma referência a uma implementação RenderEngine. Quando você quiser adicionar uma nova forma, você cria uma nova implementação dos motores de renderização que sabem sobre a nova implementação Forma e implementa a função de processamento correspondente. Você adiciona uma função virtual para Shape que atua como uma função auxiliar para selecionar a função de forma prestação correta - ou seja Círculo objetos chamar a função renderCircle () etc.

Em C ++ que poderia ser algo como:

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();
Respondeu 10/12/2008 em 04:50
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more