Disaccoppiamento delle classi dall'interfaccia utente


27

Qual è la migliore pratica quando si tratta di scrivere classi che potrebbero dover conoscere l'interfaccia utente. Una classe che sa come disegnare se stessa non infrange alcune buone pratiche poiché dipende da quale sia l'interfaccia utente (console, GUI, ecc.)?

In molti libri di programmazione mi sono imbattuto nell'esempio "Forma" che mostra l'eredità. La forma della classe base ha un metodo draw () che ogni forma come un cerchio e un quadrato hanno la precedenza. Ciò consente il polimorfismo. Ma il metodo draw () non dipende molto dall'interfaccia utente? Se scriviamo questa classe per esempio, Win Forms, non possiamo riutilizzarla per un'app console o un'app Web. È corretto?

Il motivo della domanda è che mi trovo sempre bloccato e bloccato su come generalizzare le lezioni in modo che siano più utili. Questo in realtà sta lavorando contro di me e mi chiedo se sto "provando troppo".


Perché vuoi disaccoppiare? Perché hai sentito che era la cosa giusta da fare o hai altri motivi?
SoylentGray,

2
L'intera "classe che sa come disegnare se stessa" è solo un orribile, antico esempio che vorrei scomparire. Soprattutto nello stack del programmatore del gioco =)
Patrick Hughes,

2
@Chad Non ho davvero molta esperienza fuori dalla scuola. Ho letto libri e mi piace davvero imparare e leggere cose nuove sui modelli di progettazione e sulle migliori pratiche. Quindi sì, puoi dire che ho sentito che il disaccoppiamento è buono ma ha anche senso. Voglio scrivere codice che posso usare per un'app desktop WinForms, ad esempio, quindi prendere quel codice e riutilizzarlo il più possibile per un sito Web o anche un'app Silverlight.
Pete,

@Pete - Questa è una buona risposta.
SoylentGray,

2
@Patrick: per essere onesti, se stai scrivendo una Shapeclasse, probabilmente stai scrivendo lo stack grafico stesso, non scrivendo un client nello stack grafico.
Ken Bloom,

Risposte:


13

Qual è la migliore pratica quando si tratta di scrivere classi che potrebbero dover conoscere l'interfaccia utente. Una classe che sa come disegnare se stessa non infrange alcune buone pratiche poiché dipende da quale sia l'interfaccia utente (console, GUI, ecc.)?

Dipende dalla classe e dal caso d'uso. Un elemento visivo che sa come disegnare se stesso non è necessariamente una violazione del principio della singola responsabilità.

In molti libri di programmazione mi sono imbattuto nell'esempio "Forma" che mostra l'eredità. La forma della classe base ha un metodo draw () che ogni forma come un cerchio e un quadrato hanno la precedenza. Ciò consente il polimorfismo. Ma il metodo draw () non dipende molto dall'interfaccia utente?

Ancora una volta, non necessariamente. Se puoi creare un'interfaccia (drawPoint, drawLine, set Color ecc.), Puoi praticamente passare qualsiasi contesto per disegnare cose su qualcosa alla forma, ad esempio all'interno del costruttore della forma. Ciò consentirebbe alle forme di disegnarsi su una console o su qualsiasi area di disegno.

Se scriviamo questa classe per esempio, Win Forms, non possiamo riutilizzarla per un'app console o un'app Web. È corretto?

Bene, è vero. Se si scrive un UserControl (non una classe in generale) per Windows Form, non sarà possibile utilizzarlo con una console. Ma questo non è un problema. Perché dovresti aspettarti che UserControl per Windows Form funzioni con qualsiasi tipo di presentazione? UserControl dovrebbe fare una cosa e farlo bene. È legato a una certa forma di presentazione per definizione. Alla fine, l'utente ha bisogno di qualcosa di concreto e non di un'astrazione. Questo potrebbe essere vero solo in parte per i framework, ma per le applicazioni degli utenti finali.

Tuttavia, la logica alla base dovrebbe essere disaccoppiata, quindi è possibile riutilizzarla con altre tecnologie di presentazione. Introdurre interfacce dove necessario, per mantenere l'ortogonalità per l'applicazione. La regola generale è: le cose concrete dovrebbero essere scambiabili con altre cose concrete.

Il motivo della domanda è che mi trovo sempre bloccato e bloccato su come generalizzare le lezioni in modo che siano più utili. Questo in realtà sta lavorando contro di me e mi chiedo se sto "provando troppo".

Sai, i programmatori estremi adorano il loro atteggiamento YAGNI . Non cercare di scrivere tutto in modo generico e non provare troppo a cercare di rendere tutto generico. Questo si chiama overengineering e alla fine porterà a un codice totalmente contorto. Dai a ciascun componente esattamente un compito e assicurati che lo faccia bene. Inserisci le astrazioni dove necessario, dove prevedi che le cose cambino (ad es. Interfaccia per disegnare il contesto, come indicato sopra).

In generale, quando si scrivono applicazioni aziendali, si dovrebbe sempre provare a disaccoppiare le cose. MVC e MVVM sono ottimi per disaccoppiare la logica dalla presentazione, quindi è possibile riutilizzarla per una presentazione Web o un'applicazione console. Tieni presente che alla fine alcune cose devono essere concrete. I tuoi utenti non possono lavorare con un'astrazione, hanno bisogno di qualcosa di concreto. Le astrazioni sono solo aiutanti per te, il programmatore, a mantenere il codice estensibile e gestibile. È necessario pensare a dove è necessario che il codice sia flessibile. Alla fine tutte le astrazioni devono dare alla luce qualcosa di concreto.

Modifica: se vuoi saperne di più sull'architettura e sulle tecniche di progettazione che possono fornire le migliori pratiche, ti suggerisco di leggere la risposta @Catchops e leggere le pratiche SOLID su wikipedia.

Inoltre, per cominciare, raccomando sempre il seguente libro: Head First Design Patterns . Ti aiuterà a comprendere le tecniche di astrazione / pratiche di progettazione OOP, più che nel libro GoF (che è eccellente, non è adatto ai principianti).


1
Buona risposta, ma i programmatori estremi non "mettono astrazioni dove ci aspettiamo che le cose cambino". Inseriamo astrazioni dove le cose stanno cambiando, per ASCIUGARE il codice.
Kevin Cline il

1
@kevin cline è fantastico a meno che non si stia progettando una libreria pubblicamente disponibile con un'API che deve essere conforme al comportamento e alle interfacce precedenti.
Magnus Wolffelt,

@Magnus - sì, progettare una libreria in alcune lingue, pianificare la compatibilità binaria all'indietro, è complicato. Uno è costretto a scrivere tutti i tipi di codice attualmente non necessario per consentire l'estensione futura. Questo può essere ragionevole per le lingue che si compilano sul metallo. È sciocco per i linguaggi che vengono compilati in una macchina virtuale.
Kevin Cline il

19

Hai perfettamente ragione. E no, stai "provando bene" :)

Leggi il principio della responsabilità unica

Il tuo funzionamento interno della classe e il modo in cui queste informazioni dovrebbero essere presentate all'utente sono due responsabilità.

Non abbiate paura di disaccoppiare le lezioni. Raramente il problema è troppa astrazione e disaccoppiamento :)

Due modelli molto rilevanti sono Model-view-controller per applicazioni Web e Model View ViewModel per Silverlight / WPF.


1
+1 Puoi persino usare MVC per applicazioni non web, almeno ti aiuta a pensare in termini che mantengano chiare le responsabilità.
Patrick Hughes,

MVVM è silimar per MVC. MVC è principalmente per applicazioni senza stato come le app Web.
Boris Yankov,

3
-1 Nella mia esperienza uno dei problemi più comuni è la generalizzazione prematura e l'ingegneria eccessiva in generale.
dietbuddha,

3
Devi prima sapere come progettare qualcosa per ingegnerizzarlo troppo. Nella mia esperienza, il software "under-engineer" delle persone molto più spesso.
Boris Yankov,

Mentre apprezzo gli sforzi per migliorare la progettazione del software, la sostituzione di una chiamata su un'interfaccia, per una chiamata su una classe, non disaccoppia nulla semanticamente. Considera cosa succede quando usi una lingua tipizzata in modo dinamico. C'è troppa enfasi sul disaccoppiamento superficiale (sintattico) e poco sul vero disaccoppiamento, nei consigli forniti nella sezione programmatori dello scambio di stack.
Frank Hileman,

7

Uso molto MVVM e, secondo me, una classe di oggetti business non dovrebbe mai aver bisogno di sapere nulla sull'interfaccia utente. Sicuramente potrebbero aver bisogno di conoscere il SelectedItem, o IsChecked, o IsVisible, ecc., Ma quei valori non devono essere collegati a nessuna particolare interfaccia utente e possono essere proprietà generiche sulla classe.

Se hai bisogno di fare qualcosa per l'interfaccia nel codice dietro, come impostare Focus, eseguire un'animazione, gestire i tasti di scelta rapida, ecc., Il codice dovrebbe essere parte del code-behind dell'interfaccia utente, non delle classi di logica aziendale.

Quindi direi di non smettere di cercare di dividere la tua UI e le tue classi. Più sono disaccoppiati, più sono facili da mantenere e testare.


5

Ci sono un certo numero di modelli di design collaudati che sono stati sviluppati nel corso degli anni per rispondere esattamente a ciò di cui stai parlando. Altre risposte alla tua domanda hanno fatto riferimento al principio di responsabilità singola - che è assolutamente valido - e ciò che sembra guidare la tua domanda. Tale principio afferma semplicemente che una classe deve fare BENE una cosa. In altre parole, aumentare la coesione e abbassare l'accoppiamento, che è il buon design orientato agli oggetti: una classe fa bene una cosa e non ha molte dipendenze dagli altri.

Bene ... hai ragione nell'osservare che se vuoi disegnare un cerchio su un iPhone, sarà diverso che disegnarne uno su un PC con Windows. DEVI avere (in questo caso) una classe concreta che ne disegna una bene sull'iPhone e un'altra che ne disegna una bene su un PC. Questo è il punto in cui il tenore di eredità OO di base che tutti questi esempi di forme si interrompe. Semplicemente non puoi farlo solo con l'eredità.

È qui che entrano in gioco le interfacce - come afferma la banda di quattro libri (DEVE LEGGERE) - Favorire sempre l'implementazione rispetto all'eredità. In altre parole, utilizzare le interfacce per mettere insieme un'architettura in grado di eseguire varie funzioni in molti modi senza fare affidamento su dipendenze codificate.

Ho visto riferimento ai principi SOLIDI . Sono fantastici. La "S" è il principio della singola responsabilità. MA, la "D" sta per inversione di dipendenza. Qui è possibile utilizzare il modello di inversione del controllo (Iniezione delle dipendenze). È molto potente e può essere utilizzato per rispondere alla domanda su come progettare un sistema in grado di disegnare un cerchio per un iPhone e uno per il PC.

È possibile creare un'architettura che contenga regole aziendali comuni e accesso ai dati, ma che disponga di varie implementazioni delle interfacce utente utilizzando questi costrutti. Aiuta davvero, tuttavia, essere stato in una squadra che lo ha implementato e vederlo in azione per capirlo davvero.

Questa è solo una rapida risposta di alto livello a una domanda che merita una risposta più dettagliata. Ti incoraggio a approfondire questi schemi. Qualche implementazione più concreta di questi schemi può essere trovata come nomi ben noti di MVC e MVVM.

In bocca al lupo!


Adoro quando qualcuno vota verso il basso qualcosa senza dare un commento sul perché (sarcasmo, ovviamente). I principi che ho affermato sono veri: il downvoter dovrebbe alzarsi e dire perché.
Catchops

2

Qual è la migliore pratica quando si tratta di scrivere classi che potrebbero dover conoscere l'interfaccia utente.

Una classe che sa come disegnare se stessa non infrange alcune buone pratiche poiché dipende da quale sia l'interfaccia utente (console, GUI, ecc.)?

In questo caso è ancora possibile utilizzare MVC / MVVM e iniettare diverse implementazioni dell'interfaccia utente utilizzando l'interfaccia comune:

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);

In questo modo sarai in grado di riutilizzare la logica del controller e del modello e di aggiungere nuovi tipi di GUI.


2

Esistono diversi modelli per farlo: MVP, MVC, MVVM, ecc ...

Un bell'articolo di Martin Fowler (grande nome) da leggere è GUI Architectures: http://www.martinfowler.com/eaaDev/uiArchs.html

MVP non è stato ancora menzionato, ma merita sicuramente di essere citato: dai un'occhiata.

È il modello suggerito dagli sviluppatori di Google Web Toolkit da usare, è davvero pulito.

Puoi trovare codice reale, esempi reali e motivazioni sul perché questo approccio è utile qui:

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

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

Uno dei vantaggi di seguire questo o simili approcci che non è stato sottolineato abbastanza qui è la testabilità! In molti casi direi che è il vantaggio principale!


1
+1 per i collegamenti. Stavo leggendo un articolo simile su MSDN su MVVM e quegli articoli di Google sono molto meglio se su uno schema leggermente diverso.
Pete,

1

Questo è uno dei luoghi in cui OOP non riesce a fare un buon lavoro in astrazione. Il polimorfismo OOP utilizza l'invio dinamico su una singola variabile ("questo"). Se il polimorfismo era radicato su Shape, non è possibile inviare alleati polimorfici sul renderer (console, GUI ecc.).

Considera un sistema di programmazione che potrebbe essere inviato su due o più variabili:

poly_draw(Shape s, Renderer r)

e supponiamo anche che il sistema possa darti un modo per esprimere poly_draw per varie combinazioni di tipi Shape e Renderer. Sarebbe quindi facile elaborare una classificazione di forme e renderer, giusto? Il controllo del tipo ti aiuterebbe in qualche modo a capire se c'erano combinazioni di forma e renderer che potresti non aver implementato.

La maggior parte dei linguaggi OOP non supporta nulla di simile (alcuni lo fanno, ma non sono mainstream). Ti suggerirei di dare un'occhiata al modello di Visitatore per una soluzione alternativa.


1

... il metodo draw () non dipende molto dall'interfaccia utente? Se scriviamo questa classe per esempio, Win Forms, non possiamo riutilizzarla per un'app console o un'app Web. È corretto?

Sopra suona corretto per me. Secondo la mia comprensione, si può dire che significa accoppiamento relativamente stretto tra Controller e View in termini di modello di progettazione MVC. Ciò significa anche che per passare da desktop-console-webapp si dovrà di conseguenza passare sia Controller che View come coppia - solo il modello rimane invariato.

... Mi ritrovo sempre bloccato e impiccato su come generalizzare le lezioni in modo che siano molto utili.

Bene, la mia opinione attuale è che questo accoppiamento View-Controller di cui stiamo parlando è OK e ancora di più, è piuttosto alla moda nel design moderno.

Anche se un anno o due fa mi sentivo insicuro al riguardo. Ho cambiato idea dopo aver studiato le discussioni al forum Sun su schemi e progettazione OO.

Se sei interessato, prova questo forum da solo: ora è migrato su Oracle ( link ). Se ci arrivi, prova a fare un ping al ragazzo Saish - allora, le sue spiegazioni su queste questioni difficili mi sono state molto utili. Non so dire se parteciperà ancora - io stesso non ci sono stato per un bel po '


1

Ma il metodo draw () non dipende molto dall'interfaccia utente?

Da un tipo di vista pragmatico, alcuni codici nel tuo sistema devono sapere come disegnare qualcosa come un Rectanglese questo è un requisito di fine utente. E questo a un certo punto si ridurrà a fare cose di basso livello come rasterizzare i pixel o visualizzare qualcosa in una console.

La domanda per me dal punto di vista dell'accoppiamento è chi / cosa dovrebbe dipendere da questo tipo di informazioni, e da quale grado di dettaglio (quanto astratto, ad esempio)?

Capacità di disegno / rendering astratte

Perché se il codice di disegno di livello superiore dipende solo da qualcosa di molto astratto, quell'astrazione potrebbe essere in grado di funzionare (attraverso la sostituzione di implementazioni concrete) su tutte le piattaforme che si intende targetizzare. Ad esempio, alcune IDrawerinterfacce molto astratte potrebbero essere implementate in entrambe le API della console e della GUI per fare cose come le forme della trama (l'implementazione della console potrebbe trattare la console come qualche "immagine" 80xN con l'arte ASCII). Naturalmente questo è un esempio inventato dal momento che di solito non è ciò che si desidera fare è trattare un output della console come un buffer di immagine / frame; in genere, la maggior parte delle esigenze dell'utente finale richiede più interazioni testuali nelle console.

Un'altra considerazione è quanto è facile progettare un'astrazione stabile? Perché potrebbe essere facile se tutto ciò che stai prendendo di mira sono le moderne API della GUI per sottrarre le funzionalità di base del disegno di forma come tracciare linee, rettangoli, percorsi, testo, cose di questo tipo (solo una semplice rasterizzazione 2D di un insieme limitato di primitive) , con un'unica interfaccia astratta che può essere facilmente implementata per tutti loro attraverso vari sottotipi con costi ridotti. Se riesci a progettare un'astrazione del genere in modo efficace e implementarla su tutte le piattaforme di destinazione, direi che è un male molto minore, se non addirittura un male, per una forma o un controllo della GUI o qualsiasi altra cosa sapere come disegnarsi usando un tale astrazione.

Supponiamo che tu stia cercando di sottrarre i dettagli cruenti che variano tra una Playstation portatile, un iPhone, un XBox One e un potente PC da gioco, mentre le tue esigenze sono di utilizzare le più avanzate tecniche di rendering / ombreggiatura 3D in tempo reale su ognuna . In tal caso, provare a trovare un'interfaccia astratta per sottrarre i dettagli di rendering quando le funzionalità hardware e le API sottostanti variano così selvaggiamente è quasi certo che si tradurrà in tempi enormi di progettazione e riprogettazione, un'alta probabilità di cambiamenti di progettazione ricorrenti con imprevisti scoperte, e allo stesso modo una soluzione con il minimo comune denominatore che non riesce a sfruttare la piena unicità e la potenza dell'hardware sottostante.

Far scorrere le dipendenze verso progetti stabili e "facili"

Nel mio campo sono in quest'ultimo scenario. Puntiamo a un sacco di hardware diverso con capacità e API sottostanti radicalmente diverse e provare a trovare un'astrazione di rendering / disegno per dominarli è del tutto senza speranza (potremmo diventare famosi in tutto il mondo semplicemente facendo ciò efficacemente come sarebbe un gioco cambia nel settore). Quindi l'ultima cosa che voglio nel mio caso è come il analogica Shapeo Modelo Particle Emitterche sa come disegnare se stesso, anche se si sta esprimendo che il disegno nel più alto livello e possibili vie più astratta ...

... perché quelle astrazioni sono troppo difficili da progettare correttamente, e quando un progetto è difficile da correggere, e tutto dipende da esso, questa è una ricetta per i cambiamenti di progettazione centrale più costosi che si increspano e rompono tutto a seconda di esso. Quindi l'ultima cosa che vuoi è che le dipendenze nei tuoi sistemi scorrano verso progetti astratti troppo difficili da correggere (troppo difficile da stabilizzare senza cambiamenti intrusivi).

Difficile Dipende da Facile, Non Facile Dipende da Difficile

Quindi quello che facciamo invece è far fluire le dipendenze verso cose facili da progettare. È molto più facile progettare un "Modello" astratto che si concentra solo sulla memorizzazione di cose come poligoni e materiali e ottenere quel progetto corretto piuttosto che progettare un "Renderer" astratto che può essere effettivamente implementato (attraverso sottotipi concreti sostituibili) per servire il disegno richiede uniformemente hardware diverso da una PSP da un PC.

inserisci qui la descrizione dell'immagine

Quindi invertiamo le dipendenze dalle cose che sono difficili da progettare. Invece di far conoscere ai modelli astratti come attingere a un disegno di rendering astratto da cui dipendono tutti (e interrompere le loro implementazioni se tale progetto cambia), abbiamo invece un renderista astratto che sa come disegnare ogni oggetto astratto nella nostra scena ( modelli, emettitori di particelle, ecc.) e quindi possiamo implementare un sottotipo di rendering OpenGL per PC come RendererGl, un altro per PSP come RendererPsp, un altro per telefoni cellulari, ecc. In tal caso le dipendenze fluiscono verso progetti stabili, facili da correggere, dal renderer a vari tipi di entità (modelli, particelle, trame, ecc.) nella nostra scena, non viceversa.

inserisci qui la descrizione dell'immagine

  • Sto usando "stabilità / instabilità" in un senso leggermente diverso dalla metrica degli accoppiamenti afferenti / efferenti di zio Bob che sta misurando più la difficoltà del cambiamento per quanto posso capire. Sto parlando di più sulla "probabilità di richiedere un cambiamento", sebbene la sua metrica di stabilità sia utile lì. Quando la "probabilità di cambiamento" è proporzionale alla "facilità di cambiamento" (es: le cose che hanno maggiori probabilità di richiedere cambiamenti hanno la massima instabilità e accoppiamenti afferenti dalla metrica dello zio Bob), allora tali cambiamenti probabili sono economici e non invadenti da rendere , che richiede solo la sostituzione di un'implementazione senza toccare alcun progetto centrale.

Se ti ritrovi a cercare di sottrarre qualcosa a livello centrale della tua base di codice ed è troppo difficile da progettare, invece di battere testardamente contro i muri e apportare costantemente modifiche invasive ogni mese / anno che richiedono l'aggiornamento di 8.000 file di origine perché è rompendo tutto ciò che dipende da esso, il mio suggerimento numero uno è di considerare di invertire le dipendenze. Vedi se riesci a scrivere il codice in modo tale che la cosa che è così difficile da progettare dipende da tutto ciò che è più facile da progettare, non avere le cose che sono più facili da progettare a seconda della cosa che è così difficile da progettare. Tieni presente che sto parlando di progetti (in particolare progetti di interfacce) e non di implementazioni: a volte le cose sono facili da progettare e difficili da implementare, e a volte le cose sono difficili da progettare ma facili da implementare. Le dipendenze scorrono verso i progetti, quindi l'attenzione dovrebbe essere solo su quanto sia difficile progettare qualcosa qui per determinare la direzione in cui scorrono le dipendenze.

Principio unico di responsabilità

Per me SRP non è così interessante qui di solito (anche se dipende dal contesto). Voglio dire, c'è un atto di bilanciamento sul filo del rasoio nel progettare cose che siano chiare nello scopo e mantenibili, ma i tuoi Shapeoggetti potrebbero dover esporre informazioni più dettagliate se non sanno come disegnare se stessi, per esempio, e potrebbero non esserci molte cose significative da fare con una forma in un contesto d'uso particolare che costruirla e disegnarla. Ci sono compromessi con quasi tutto, e non è correlato a SRP che può rendere le cose consapevoli di come trarre se stessi capaci di diventare un incubo di mantenimento nella mia esperienza in determinati contesti.

Ha molto più a che fare con l'accoppiamento e la direzione in cui fluiscono le dipendenze nel sistema. Se stai provando a eseguire il porting di un'interfaccia di rendering astratta da cui tutto dipende (perché la stanno usando per disegnare se stessi) su una nuova API / hardware di destinazione e ti rendi conto che devi cambiare notevolmente il suo design per farlo funzionare efficacemente lì, quindi è una modifica molto costosa da apportare che richiede la sostituzione di implementazioni di tutto ciò che nel tuo sistema sa come disegnare. E questo è il problema di manutenzione più pratico che incontro con le cose consapevoli di come disegnare se stessi che si traduce in un carico di dipendenze che scorre verso astrazioni che sono troppo difficili da progettare correttamente in anticipo.

Orgoglio degli sviluppatori

Cito questo punto perché, nella mia esperienza, questo è spesso il più grande ostacolo a indirizzare la direzione delle dipendenze verso cose più facili da progettare. È molto facile per gli sviluppatori diventare un po 'ambiziosi qui e dire: "Progetterò l'astrazione di rendering multipiattaforma per dominarli tutti, risolverò ciò che gli altri sviluppatori trascorrono mesi in porting e otterrò giusto e funzionerà come per magia su ogni singola piattaforma che supportiamo e utilizziamo le tecniche di rendering all'avanguardia su ognuno; l'ho già immaginato nella mia testa ".Nel qual caso resistono alla soluzione pratica che è quella di evitare di farlo e capovolgere la direzione delle dipendenze e tradurre ciò che potrebbe essere enormemente costoso e le ricorrenti modifiche alla progettazione centrale in semplici modifiche ricorrenti economiche e locali all'implementazione. C'è bisogno di una sorta di istinto di "bandiera bianca" negli sviluppatori per arrendersi quando qualcosa è troppo difficile da progettare a un livello così astratto e riconsiderare la loro intera strategia, altrimenti si trovano in un sacco di dolore e sofferenza. Suggerirei di trasferire tali ambizioni e spirito combattivo a implementazioni all'avanguardia di una cosa più semplice da progettare piuttosto che portare tali ambizioni che conquistano il mondo a livello di progettazione dell'interfaccia.


1
Non riesco a cogliere l'idea di "invertire le dipendenze dalle cose che sono difficili da progettare", stai parlando solo di eredità? Usando l'esempio di PSP / OpenGL, intendi invece di creare un OpenGLBillboard, faresti uno OpenGLRendererche sa come disegnare qualsiasi tipo di IBillBoard? Ma lo farebbe delegando la logica a IBillBoard, o avrebbe enormi switch o IBillBoardtipi con condizionali? Questo è ciò che trovo difficile da capire, perché non sembra affatto sostenibile!
Steve Chamaillard,

@SteveChamaillard La differenza è, diciamo, che PSP (hardware limitato) deve gestire le primitive di volume usando la trasparenza dello screendor della vecchia scuola e un diverso ordinamento della valutazione del rendering: digitalrune.github.io/DigitalRune-Documentation/media/… . Quando ne hai uno centrale RendererPspche conosce le astrazioni di alto livello della tua scena di gioco, può quindi fare tutta la magia e i backflip necessari per rendere tali cose in un modo che sembra convincente sulla PSP ....
Dragon Energy

Mentre se avevi tali primitive di volume che richiedevano il rendering di se stessi, o le loro operazioni sono così di alto livello che si stanno sostanzialmente specificando il rendering (il che non fa alcuna differenza se non la ridondanza rotonda e l'ulteriore accoppiamento), oppure l'astrazione del renderer è incapace di davvero fare le cose nel modo più efficace possibile sulla PSP (almeno senza fare backflip, cosa che non avrebbe bisogno di fare se le dipendenze fossero invertite).
Dragon Energy,

1
Ok, penso di averlo ora. Fondamentalmente stai dicendo che tali preoccupazioni (cioè l'hardware) sono di così alto livello che rendere BillBoardveramente difficile fare oggetti di basso livello come dipendere da quelli? Considerando che a IRendererè già un livello elevato e potrebbe dipendere da queste preoccupazioni con molti meno problemi?
Steve Chamaillard,

1
Con preoccupazioni di rendering all'avanguardia su piattaforme diverse, capacità hardware diverse, è troppo difficile progettare qualcosa in cui io sono il capo e dirgli cosa fare. È molto più facile per me dire: "Ehi, sono una persona torbida / nebbiosa con particelle acquose grigiastre come questa, e cerca di farmi apparire bene per favore, non catturarmi il collo che non mi sono rasato di recente", e lascia che il renderer capisca come rendermi nel modo più bello e in tempo reale possibile, date le limitazioni con cui sta lavorando. Qualsiasi tentativo di dirgli cosa fare porterà quasi sicuramente a un percorso controproducente.
Dragon Energy il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.