Desacoplar classes da interface do usuário


27

Qual é a melhor prática quando se trata de escrever aulas que talvez precisem saber sobre a interface do usuário. Uma classe que sabe desenhar-se não quebraria algumas práticas recomendadas, pois depende de qual é a interface do usuário (console, GUI etc.)?

Em muitos livros de programação, me deparei com o exemplo "Shape" que mostra herança. A forma da classe base possui um método draw () que cada forma, como um círculo e um quadrado, substitui. Isso permite polimorfismo. Mas o método draw () não depende muito da interface do usuário? Se escrevermos esta classe para, por exemplo, Win Forms, não poderemos reutilizá-la para um aplicativo de console ou aplicativo da web. Isso está correto?

O motivo da pergunta é que eu sempre fico preso e desligado de como generalizar as aulas para que elas sejam mais úteis. Isso está realmente funcionando contra mim e eu estou me perguntando se estou "tentando demais".


Por que você deseja desacoplar? Porque você ouviu que era a coisa certa a fazer ou você tem outros motivos?
SoylentGray

2
Toda a "classe que sabe se desenhar" é apenas um exemplo horrível e antigo que eu gostaria que desaparecesse. Especialmente na pilha do programador de jogos =)
Patrick Hughes

2
@ Chad Eu realmente não tenho muita experiência fora da escola. Eu li livros e realmente gosto de aprender e ler coisas novas sobre padrões de design e práticas recomendadas. Então, sim, você pode dizer que ouvi dizer que a dissociação é boa, mas também faz sentido. Quero escrever um código que possa ser usado para um aplicativo WinForms para desktop, por exemplo, e depois pegar esse código e reutilizá-lo o máximo possível para um site ou mesmo um aplicativo silverlight.
Pete

@Pete - Essa é uma boa resposta.
SoylentGray

2
@ Patrick: para ser justo, se você está escrevendo uma Shapeclasse, provavelmente está escrevendo a própria pilha de gráficos, não escrevendo um cliente na pilha de gráficos.
Ken Bloom

Respostas:


13

Qual é a melhor prática quando se trata de escrever aulas que talvez precisem saber sobre a interface do usuário. Uma classe que sabe desenhar-se não quebraria algumas práticas recomendadas, pois depende de qual é a interface do usuário (console, GUI etc.)?

Isso depende da classe e do caso de uso. Um elemento visual que sabe se desenhar não é necessariamente uma violação do princípio da responsabilidade única.

Em muitos livros de programação, me deparei com o exemplo "Shape" que mostra herança. A forma da classe base possui um método draw () que cada forma, como um círculo e um quadrado, substitui. Isso permite polimorfismo. Mas o método draw () não depende muito da interface do usuário?

Novamente, não necessariamente. Se você pode criar uma interface (drawPoint, drawLine, definir Color etc.), pode praticamente transmitir qualquer contexto para desenhar coisas em algo na forma, por exemplo, dentro do construtor da forma. Isso permitiria que as formas se desenhassem em um console ou em qualquer tela fornecida.

Se escrevermos esta classe para, por exemplo, Win Forms, não poderemos reutilizá-la para um aplicativo de console ou aplicativo da web. Isso está correto?

Bem, isso é verdade. Se você escrever um UserControl (não uma classe em geral) para o Windows Forms, não poderá usá-lo com um console. Mas isso não é problema. Por que você esperaria que um UserControl for Windows Forms funcionasse com qualquer tipo de apresentação? O UserControl deve fazer uma coisa e fazê-lo bem. Está vinculado a uma certa forma de apresentação por definição. No final, o usuário precisa de algo concreto e não de uma abstração. Isso pode ser apenas parcialmente verdadeiro para estruturas, mas é para aplicativos de usuário final.

No entanto, a lógica por trás disso deve ser dissociada, para que você possa usá-lo novamente com outras tecnologias de apresentação. Introduzir interfaces sempre que necessário, para manter a ortogonalidade do seu aplicativo. A regra geral é: As coisas concretas devem ser trocáveis ​​com outras coisas concretas.

O motivo da pergunta é que eu sempre fico preso e desligado de como generalizar as aulas para que elas sejam mais úteis. Isso está realmente funcionando contra mim e eu estou me perguntando se estou "tentando demais".

Você sabe, programadores extremos gostam de sua atitude no YAGNI . Não tente escrever tudo de forma genérica e não tente demais fazer de tudo para fins gerais. Isso é chamado de superengenharia e, eventualmente, levará a um código totalmente complicado. Dê a cada componente exatamente uma tarefa e verifique se ela funciona bem. Coloque abstrações onde for necessário, onde você espera que as coisas mudem (por exemplo, interface para o contexto do desenho, como mencionado acima).

Em geral, ao escrever aplicativos de negócios, você deve sempre tentar desacoplar as coisas. O MVC e o MVVM são ótimos para separar a lógica da apresentação, para que você possa reutilizá-la para uma apresentação na Web ou um aplicativo de console. Lembre-se de que, no final, algumas coisas precisam ser concretas. Seus usuários não podem trabalhar com uma abstração, eles precisam de algo concreto. As abstrações são apenas auxiliares para você, programador, manter o código extensível e sustentável. Você precisa indicar onde você precisa que seu código seja flexível. Eventualmente, todas as abstrações precisam dar origem a algo concreto.

Editar: se você quiser ler mais sobre técnicas de arquitetura e design que podem fornecer práticas recomendadas, sugiro que você leia a resposta do @Catchops e leia sobre as práticas do SOLID na wikipedia.

Além disso, para iniciantes, eu sempre recomendo o seguinte livro: Head First Design Patterns . Isso o ajudará a entender as técnicas de abstração / práticas de design de POO, mais do que o livro do GoF (que é excelente, mas não é adequado para iniciantes).


1
Boa resposta, mas programadores extremos não 'colocam abstrações onde esperamos que as coisas mudem'. Colocamos em abstrações onde as coisas estão mudando, para secar o código.
Kevin cline

1
O @kevin cline é incrível, a menos que você esteja criando uma biblioteca disponível publicamente com uma API que precisa estar em conformidade com o comportamento e as interfaces anteriores.
Magnus Wolffelt

@ Magnus - sim, projetar uma biblioteca em algumas linguagens, planejar a compatibilidade binária com versões anteriores, é complicado. Um é forçado a escrever todos os tipos de códigos atualmente desnecessários para permitir futuras extensões. Isso pode ser razoável para idiomas que compilam com o metal. É bobagem para idiomas que são compilados em uma máquina virtual.
Kevin cline

19

Você está definitivamente certo. E não, você está "tentando muito bem" :)

Leia sobre o princípio da responsabilidade única

Seu trabalho interno com a classe e a maneira como essas informações devem ser apresentadas ao usuário são duas responsabilidades.

Não tenha medo de dissociar as aulas. Raramente o problema é muita abstração e desacoplamento :)

Dois padrões muito relevantes são o Model-view-controller para aplicativos da Web e o Model View ViewModel para Silverlight / WPF.


1
+1 Você pode até usar o MVC para aplicativos que não sejam da Web, pelo menos isso o ajudará a pensar em termos que mantenham as responsabilidades claras.
Patrick Hughes

MVVM é silimar para MVC. O MVC é principalmente para aplicativos sem estado, como aplicativos da web.
Boris Yankov

3
-1 Na ​​minha experiência, um dos problemas mais comuns é a generalização prematura e o excesso de engenharia em geral.
dietbuddha

3
Primeiro, você precisa saber como projetar algo para projetá-lo em excesso. Na minha experiência, as pessoas 'sub-engenheiros' de software com muito mais frequência.
Boris Yankov 29/07

Embora aprecie os esforços para melhorar o design do software, a substituição de uma chamada em uma interface por uma chamada em uma classe não dissocia nada semanticamente. Considere o que acontece ao usar um idioma digitado dinamicamente. Há muita ênfase no desacoplamento superficial (sintático) e pouca no desacoplamento verdadeiro, nos conselhos fornecidos na seção de troca de pilha dos programadores.
precisa saber é o seguinte

7

Eu uso muito o MVVM e, na minha opinião, uma classe de objeto de negócios nunca precisa saber nada sobre a interface do usuário. Claro que eles podem precisar conhecer o SelectedItem, ou IsChecked, ou IsVisibleetc, mas esses valores não precisam se vincular a nenhuma interface do usuário específica e podem ser propriedades genéricas na classe.

Se você precisar fazer algo com a interface no código por trás, como definir o Focus, executar uma animação, manipular teclas de atalho etc., o código deve fazer parte do código por trás da interface do usuário, não das classes de lógica de negócios.

Então, eu diria que não pare de tentar dividir sua interface do usuário e suas classes. Quanto mais dissociados, mais fáceis são de manter e testar.


5

Há vários padrões de design testados e aprovados que foram desenvolvidos ao longo dos anos para tratar exatamente do que você está falando. Outras respostas à sua pergunta se referiram ao Princípio Único de Responsabilidade - que é absolutamente válido - e ao que parece estar direcionando sua pergunta. Esse princípio simplesmente afirma que uma classe precisa fazer uma coisa BEM. Em outras palavras, aumentar a coesão e diminuir o acoplamento, que é o objetivo do bom design orientado a objetos - uma classe faz uma coisa bem e não tem muitas dependências das outras.

Bem ... você está certo ao observar que, se quiser desenhar um círculo em um iPhone, será diferente de desenhar um círculo em um PC executando o Windows. Você DEVE ter (neste caso) uma classe concreta que desenhe um poço no iPhone e outra que desenhe um poço no PC. É aqui que o legado básico da herança OO que todos esses exemplos de formas se decompõem. Você simplesmente não pode fazê-lo apenas com herança.

É aí que as interfaces entram - como afirma o livro da Gangue dos Quatro (DEVE LER) - Sempre favorecem a implementação sobre a herança. Em outras palavras, use interfaces para reunir uma arquitetura que possa executar várias funções de várias maneiras, sem depender de dependências codificadas.

Eu já vi referência aos princípios do SOLID . Essas são ótimas. O 'S' é o princípio da responsabilidade única. MAS, o 'D' significa Inversão de Dependência. O padrão Inversão de Controle (Injeção de Dependência) pode ser usado aqui. É muito poderoso e pode ser usado para responder à pergunta de como arquitetar um sistema que pode desenhar um círculo para um iPhone e outro para o PC.

É possível criar uma arquitetura que contenha regras comerciais comuns e acesso a dados, mas tenha várias implementações de interfaces com o usuário usando essas construções. Realmente ajuda, no entanto, estar em uma equipe que o implementou e vê-lo em ação para realmente entendê-lo.

Esta é apenas uma resposta rápida de alto nível a uma pergunta que merece uma resposta mais detalhada. Encorajo-vos a olhar mais para esses padrões. Uma implementação mais concreta desses padrões pode ser encontrada, assim como nomes conhecidos de MVC e MVVM.

Boa sorte!


Adoro quando alguém rejeita algo sem comentar o porquê (sarcasmo, é claro). Os princípios que afirmei são verdadeiros - o downvoter se levantaria e diria o porquê.
Catch1

2

Qual é a melhor prática quando se trata de escrever aulas que talvez precisem saber sobre a interface do usuário.

Uma classe que sabe desenhar-se não quebraria algumas práticas recomendadas, pois depende de qual é a interface do usuário (console, GUI etc.)?

Nesse caso, você ainda pode usar o MVC / MVVM e injetar diferentes implementações da interface do usuário usando a interface comum:

public interface IAgnosticChartDrawing
{
   public void Draw(ChartProperties chartProperties);
   event EventHandler ChartPanned;
}

public class GuiChartDrawer : UserControl, IAgnosticChartDrawing
{
    public void Draw(ChartProperties chartProperties)
    {
        //GDI, GTK or something else...
    }

    //Implement event based on mouse actions
}

public class ConsoleChartDrawer : IAgnosticChartDrawing
{
    public void Draw(ChartProperties chartProperties)
    {
        //'Draw' using characters and symbols...
    }

    //Implement event based on keyboard actions
}

IAgnosticChartDrawing guiView = new GuiChartDrawer();
IAgnosticChartDrawing conView = new ConsoleChartDrawer();

Model model = new FinancialModel();

SampleController controllerGUI = new SampleController(model, guiView);
SampleController controllerConsole = new SampleController(model, conView);

Dessa forma, você poderá reutilizar sua lógica de Controlador e Modelo enquanto poderá adicionar novos tipos de GUI.


2

Existem diferentes padrões para fazer isso: MVP, MVC, MVVM, etc ...

Um bom artigo de Martin Fowler (grande nome) para ler é GUI Architectures: http://www.martinfowler.com/eaaDev/uiArchs.html

O MVP ainda não foi mencionado, mas definitivamente merece ser citado: dê uma olhada nele.

É o padrão sugerido pelos desenvolvedores do Google Web Toolkit, é realmente legal.

Você pode encontrar código real, exemplos reais e justificativas sobre por que essa abordagem é útil aqui:

http://code.google.com/webtoolkit/articles/mvp-architecture.html

http://code.google.com/webtoolkit/articles/mvp-architecture-2.html

Uma das vantagens de seguir esta ou outras abordagens semelhantes que não foram enfatizadas o suficiente aqui é a testabilidade! Em muitos casos, eu diria que essa é a principal vantagem!


1
+1 para os links. Eu estava lendo um artigo semelhante no MSDN sobre MVVM e esses artigos do Google são muito melhores, embora com um padrão um pouco diferente.
Pete

1

Este é um dos lugares onde o OOP falha em fazer um bom trabalho na abstração. O polimorfismo OOP usa despacho dinâmico sobre uma única variável ('this'). Se o polimorfismo estiver enraizado no Shape, você não poderá despachar polimorficamente no renderizador (console, GUI etc.).

Considere um sistema de programação que possa despachar em duas ou mais variáveis:

poly_draw(Shape s, Renderer r)

e também suponha que o sistema possa fornecer uma maneira de expressar poly_draw para várias combinações de tipos de forma e tipos de renderizador. Seria fácil criar uma classificação de formas e renderizadores, certo? O verificador de tipos de alguma forma ajudaria você a descobrir se havia combinações de forma e renderizador que você pode ter perdido na implementação.

A maioria dos idiomas OOP não suporta nada como o descrito acima (alguns o fazem, mas eles não são comuns). Eu sugiro que você dê uma olhada no padrão Visitor para uma solução alternativa.


1

... o método draw () não depende muito da interface do usuário? Se escrevermos esta classe para, por exemplo, Win Forms, não poderemos reutilizá-la para um aplicativo de console ou aplicativo da web. Isso está correto?

Acima parece correto para mim. Pelo meu entendimento, pode-se dizer que significa um acoplamento relativamente apertado entre o Controller e o View em termos de padrão de design do MVC. Isso também significa que, para alternar entre o desktop-console-webapp, será necessário alternar o Controller e o View como um par - apenas o modelo permanece inalterado.

... Eu sempre fico preso e desligado de como generalizar as aulas para que sejam mais úteis.

Bem, minha opinião atual acima é que esse acoplamento View-Controller de que estamos falando está OK e, mais ainda, está bastante moderno no design moderno.

Porém, há um ou dois anos, eu também me sentia insegura sobre isso. Mudei de idéia depois de estudar as discussões no fórum da Sun sobre padrões e design de OO.

Se você estiver interessado, experimente este fórum - ele foi migrado para o Oracle agora ( link ). Se você chegar lá, tente fazer o ping no cara Saish - na época, suas explicações sobre esses assuntos complicados se revelaram muito úteis para mim. Não sei dizer se ele ainda participa - eu mesmo não estou lá há um bom tempo


1

Mas o método draw () não depende muito da interface do usuário?

De um ponto de vista pragmático, algum código em seu sistema precisa saber como desenhar algo como um Rectanglese esse for um requisito para o usuário final. Em algum momento, isso se resumirá em fazer coisas realmente de baixo nível, como rasterizar pixels ou exibir algo em um console.

A questão para mim do ponto de vista do acoplamento é quem / o que deve depender desse tipo de informação e com que grau de detalhe (quão abstrato, por exemplo)?

Abstraindo as capacidades de desenho / renderização

Como se o código de desenho de nível superior depender apenas de algo muito abstrato, essa abstração poderá funcionar (através da substituição de implementações concretas) em todas as plataformas que você pretende direcionar. Como exemplo artificial, alguma IDrawerinterface muito abstrata pode ser implementada nas APIs do console e da GUI para fazer coisas como formas de plotagem (a implementação do console pode tratar o console como uma "imagem" de 80xN com arte ASCII). Claro que esse é um exemplo artificial, já que geralmente não é o que você quer fazer é tratar uma saída do console como um buffer de imagem / quadro; normalmente, a maioria das necessidades do usuário final exige mais interações baseadas em texto nos consoles.

Outra consideração é como é fácil projetar uma abstração estável? Porque pode ser fácil se tudo o que você está alvejando são as modernas APIs da GUI para abstrair os recursos básicos de desenho de formas, como traçar linhas, retângulos, caminhos, texto, coisas desse tipo (apenas rasterização 2D simples de um conjunto limitado de primitivas) , com uma interface abstrata que pode ser facilmente implementada para todos eles através de vários subtipos com pouco custo. Se você pode projetar essa abstração de maneira eficaz e implementá-la em todas as plataformas de destino, eu diria que é um mal muito menor, mesmo que seja um mal, para uma forma ou controle de GUI ou qualquer outra coisa que saiba como se desenhar usando esse abstração.

Mas digamos que você esteja tentando abstrair os detalhes sangrentos que variam entre um Playstation Portable, iPhone, um XBox One e um poderoso PC para jogos, enquanto suas necessidades são utilizar as mais avançadas técnicas de renderização / sombreamento 3D em tempo real de cada uma. . Nesse caso, tentar criar uma interface abstrata para abstrair os detalhes de renderização quando os recursos e APIs de hardware subjacentes variarem muito, quase certamente resultará em um tempo enorme de design e redesenho, uma alta probabilidade de mudanças de design recorrentes com imprevistos. descobertas e da mesma forma uma solução de denominador comum mais baixo que falha ao explorar a exclusividade e o poder completos do hardware subjacente.

Fazendo com que as dependências fluam para projetos estáveis ​​e "fáceis"

No meu campo, estou nesse último cenário. Temos como alvo muitos hardwares diferentes, com recursos e APIs subjacentes radicalmente diferentes, e tentar criar uma abstração de renderização / desenho para governá-los é algo sem esperança (podemos tornar-nos mundialmente famosos apenas fazendo isso com eficácia, pois seria um jogo trocador na indústria). Assim, a última coisa que eu quero no meu caso é como a analógica Shapeou Modelou Particle Emitterque sabe como desenhar a si próprio, mesmo se ele está expressando que o desenho no mais alto nível e forma mais abstrato possível ...

... porque essas abstrações são muito difíceis de projetar corretamente, e quando um projeto é difícil de corrigir, e tudo depende disso, essa é uma receita para as alterações de projeto central mais caras que ondulam e quebram tudo, dependendo dele. Portanto, a última coisa que você deseja é que as dependências em seus sistemas fluam para projetos abstratos muito difíceis de serem corrigidos (muito difíceis de estabilizar sem alterações intrusivas).

Difícil Depende de Fácil, Não Fácil Depende de Difícil

Então, o que fazemos é fazer com que as dependências fluam em direção a coisas fáceis de projetar. É muito mais fácil projetar um "Modelo" abstrato, focado apenas no armazenamento de coisas como polígonos e materiais e obter esse design correto do que projetar um "Renderer" abstrato que possa ser efetivamente implementado (por meio de subtipos de concreto substituíveis) para servir ao desenho solicita uniformemente um hardware tão díspar quanto um PSP a partir de um PC.

insira a descrição da imagem aqui

Portanto, invertemos as dependências das coisas difíceis de projetar. Em vez de fazer com que os modelos abstratos saibam desenhar-se para um design de renderizador abstrato do qual todos eles dependem (e quebre suas implementações se esse design mudar), temos um renderizador abstrato que sabe como desenhar todos os objetos abstratos em nossa cena ( modelos, emissores de partículas, etc.) e, portanto, podemos implementar um subtipo de renderizador OpenGL para PCs RendererGl, outro para PSPs RendererPsp, outro para celulares etc. Nesse caso, as dependências estão fluindo para projetos estáveis, fáceis de corrigir, do renderizador a vários tipos de entidades (modelos, partículas, texturas etc.) em nossa cena, e não o contrário.

insira a descrição da imagem aqui

  • Estou usando "estabilidade / instabilidade" em um sentido ligeiramente diferente da métrica de acoplamentos aferentes / eferentes do tio Bob, que está medindo mais a dificuldade da mudança, tanto quanto eu possa entender. Estou falando mais sobre "probabilidade de exigir mudanças", embora sua métrica de estabilidade seja útil lá. Quando a "probabilidade de mudança" é proporcional à "facilidade de mudança" (por exemplo: as coisas com maior probabilidade de exigir mudanças têm a mais alta instabilidade e acoplamentos aferentes da métrica do tio Bob), essas alterações prováveis ​​são baratas e não intrusivas. , exigindo apenas a substituição de uma implementação sem tocar em nenhum design central.

Se você está tentando abstrair algo em um nível central da sua base de código e é muito difícil projetar, em vez de bater de cabeça teimosamente contra paredes e fazer constantemente alterações intrusivas a cada mês / ano, que exigem a atualização de 8.000 arquivos de origem, porque é quebrando tudo o que depende, minha sugestão número um é considerar a inversão das dependências. Veja se você pode escrever o código de uma maneira que a coisa que é tão difícil de projetar depende de tudo o que é mais fácil de projetar, sem ter as coisas que são mais fáceis de projetar, dependendo da coisa que é tão difícil de projetar. Observe que estou falando de designs (especificamente designs de interfaces) e não de implementações: às vezes, as coisas são fáceis de projetar e difíceis de implementar, e às vezes as coisas são difíceis de projetar, mas fáceis de implementar. As dependências fluem para os projetos; portanto, o foco deve ser apenas o quão difícil é projetar aqui para determinar a direção em que as dependências fluem.

Princípio da responsabilidade única

Para mim, o SRP não é tão interessante aqui normalmente (embora dependendo do contexto). Quero dizer, há um ato de equilibrar a corda bamba ao projetar coisas que são claras de propósito e de manutenção, mas seus Shapeobjetos podem precisar expor informações mais detalhadas se não souberem se desenhar, por exemplo, e talvez não haja muitas coisas significativas para faça com uma forma em um contexto de uso específico do que construa e desenhe. Há trocas com quase tudo, e não está relacionado ao SRP que pode tornar as coisas conscientes de como se tornar capaz de se tornar um pesadelo de manutenção na minha experiência em determinados contextos.

Tem muito mais a ver com acoplamento e a direção na qual as dependências fluem no seu sistema. Se você estiver tentando portar uma interface de renderização abstrata da qual tudo depende (porque eles a estão usando para se desenhar) para uma nova API / hardware de destino e perceber que você precisa alterar consideravelmente o design para fazê-la funcionar efetivamente lá, é uma alteração muito cara a ser feita, que requer a substituição de implementações de tudo em seu sistema que sabe como se desenhar. E esse é o problema de manutenção mais prático que encontro com as coisas que sabem como se desenhar, se isso se traduz em um monte de dependências fluindo em direção a abstrações que são muito difíceis de projetar corretamente com antecedência.

Orgulho do desenvolvedor

Mencionei esse ponto porque, na minha experiência, esse costuma ser o maior obstáculo ao direcionamento das dependências para coisas mais fáceis de projetar. É muito fácil para os desenvolvedores ficarem um pouco ambiciosos aqui e dizer: "Vou projetar a abstração de renderização de plataforma cruzada para governar todos eles, vou resolver o que outros desenvolvedores passam meses em portar e vou conseguir certo e funcionará como mágica em todas as plataformas que suportamos e utilizamos as técnicas de renderização de ponta em cada uma; eu já imaginava isso na minha cabeça ".Nesse caso, eles resistem à solução prática, que é evitar fazê-lo, apenas mudar a direção das dependências e traduzir o que pode ser enormemente caro e recorrente nas alterações de design central para alterações simplesmente baratas e locais na implementação. É preciso haver algum tipo de instinto de "bandeira branca" nos desenvolvedores para desistir quando algo é muito difícil de projetar para um nível tão abstrato e reconsiderar toda a sua estratégia; caso contrário, eles sofrerão muito. Eu sugeriria transferir tais ambições e espírito de luta para implementações de última geração, de uma coisa mais fácil de projetar do que levar essas ambições de conquista do mundo para o nível de design de interface.


1
Não consigo entender a idéia de "inverter as dependências das coisas difíceis de projetar", você está falando apenas de herança? Usando o exemplo do PSP / OpenGL, você quer dizer que, em vez de criar um OpenGLBillboard, você faria um OpenGLRendererque sabe desenhar qualquer tipo de IBillBoard? Mas faria isso delegando a lógica IBillBoardou teria enormes opções ou IBillBoardtipos com condicionais? É isso que acho difícil de entender, porque isso não parece sustentável!
Steve Chamaillard

@SteveChamaillard A diferença é, digamos, que o PSP (hardware limitado) deve lidar com primitivas de volume usando a transparência do screendoor da velha escola e uma ordem diferente de avaliação de renderização: digitalrune.github.io/DigitalRune-Documentation/media/… . Quando você tem uma central RendererPspque conhece as abstrações de alto nível da cena do jogo, ela pode fazer toda a mágica e retroceder para renderizar essas coisas de uma maneira que pareça convincente no PSP ...
Dragon Energy

Considerando que, se você tiver essas primitivas de volume solicitando a renderização, suas operações são tão de alto nível que estão basicamente se especificando para renderizar (o que não faz diferença, exceto redundância de rotatória e acoplamento adicional), ou a abstração do renderizador é incapaz de realmente fazer as coisas da maneira mais eficaz possível no PSP (pelo menos sem fazer backflips, o que não seria necessário se as dependências fossem invertidas).
Dragon Energy

1
Ok, eu acho que entendi agora. Basicamente, você está dizendo que essas preocupações (ou seja, hardware) são de nível tão alto que BillBoardseria difícil fazer objetos de baixo nível, como uma dependência deles? Considerando que um IRendererjá é alto e pode depender dessas preocupações com muito menos problemas?
precisa

1
Com preocupações de renderização de ponta em plataformas diferentes, recursos de hardware diferentes, é muito difícil projetar algo em que eu sou o chefe e dizer o que fazer. É muito mais fácil para mim dizer: "Ei, eu sou uma coisa nublada / nebulosa com partículas aquosas acinzentadas como esta, e tente me fazer parecer bem, por favor, não capture meu pescoço que não raspei ultimamente", e deixe o renderizador descobrir como me render da maneira mais bonita e em tempo real possível, dadas as limitações com as quais está trabalhando. Qualquer tentativa de dizer o que fazer resultará quase certamente em um caminho contraproducente.
Dragon Energy
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.