Ogni oggetto dovrebbe sapere come presentare / disegnare se stessi?

8

David West nel suo libro Thinking degli oggetti (capitolo 10, sezione 1, sottosezione 2) ha proposto che in un ambiente OO ideale, ogni oggetto dovrebbe essere in grado di presentarsi su richiesta; sia per gli umani (come GUI), componenti non nativi (come JSON e / o XML), o qualsiasi altra parte interessata:

Object thinking says that a view (sometimes called an interface) —graphical or otherwise—is a means for an object to communicate with another object and nothing more. The need for a view arises when an object needs to present itself in a “non-native” form to some other object (usually a human being) or application (for example, an XML view for data objects being shared across platforms).

Discovery of the need and the parameters that must be satisfied by a view is manifest in the scenarios in which the object participates. Whenever an object is asked to display itself, it must use a view—a representation—appropriate for the sender of that display message. If, for example, an object is trying to instantiate itself (get a value for itself), it must present a view of itself as an implicit request to a human being (or other service-providing object) for a value. If we are building a GUI that will serve as an intermediary between a software object and a human object, we will use glyphs for display purposes and widgets for interaction purposes.

But which glyphs and widgets need to be included in the GUI ? Only those necessary to complete the scenario or scenarios 4 of immediate interest as the application runs. This perspective is counterintuitive for most developers because it suggests that a GUI be defined from the application out.

As an example, consider a brewery. Off to one side are vats filled with beer. At the a complex production line consisting of bottle washers, filler stations, capping machines, and package assemblers. Above it all is a control station that monitors the brewery and notifies human managers of status and problems. Traditional developers are likely to begin their analysis and design of “a brewery management system” from the point of view of the control panel. This is analogous to designing from the interface in.

Object thinking would suggest, instead, that you consider which object is the prime customer of the brewery and all its myriad machines. On whose behalf does the complex maze of equipment exist? The correct business answer is, of course, “The customer.” But an answer more reflective of object thinking is, “The beer.” All scenarios are written from the perspective of the beer, trying to get itself into a bottle, with a cap, placed in a package, and resident in a truck. The control panel is a passive observer 5 of the state of the brewery. If the beer encounters a problem at some point, it’s the responsibility of the beer to request intervention of the human operators by sending a message to the control panel (or machine-specific control panels) requesting an intervention service.

This perspective will simplify GUI design and, more important, eliminate the host of manager and controller objects that seem to inevitably arise when designing from the control panel’s ( GUI ’s) perspective.

Venendo da un principiante nel mondo OO: dovrebbe essere proprio questo il caso?

Avere oggetti che sanno come rappresentarsi sicuramente potrebbe ridurre il numero di oggetti controller / manager che West ha ripetutamente affermato nel suo libro che un Thinker degli oggetti dovrebbe cercare di evitare a tutti i costi. Ma non rispettando questa "regola" interrompi SRP ?

Inoltre (se risulta essere il caso), data un'implementazione tipica, ad esempio, in un'applicazione Android: come si può raggiungere questo tipo di obiettivo? Se ogni oggetto che creiamo sa come presentarsi come View ?

    
posta ridsatrio 29.03.2016 - 17:01
fonte

3 risposte

11

Penso che questa sia una delle cose più difficili da capire sul design di OO e onestamente, penso che molti autori abbiano torto e / o non lo spieghino molto bene. Molte persone sbagliano e non riescono mai a capirlo. Prendiamo un esempio che non è basato sulla GUI ma si imbatte nello stesso errore.

In Java, ogni oggetto ha un metodo uguale. Quindi hai tipi di collezioni come set e map che dipendono da questo metodo per determinare quando gli oggetti devono essere aggiunti alla collezione o quando sono duplicati. Questo sembra un buon OO per molte persone. Il problema è che ciò che si finisce è un oggetto (la collezione) il cui comportamento non è determinato da esso ma dagli oggetti che contiene. Questo è un po 'come avere i passeggeri sul bus diretti dove dovrebbe andare. Cosa succede se non sono d'accordo? Questo non è un problema teorico, è un problema davvero spinoso in cui devi fondamentalmente interrompere l'ereditarietà per prevenire i bug nel tuo programma. Prendi una forma e una forma colorata. Un quadrato 2x2 corrisponde a un quadrato blu 2x2? Shape dice "sì" e ColoredShape dice "no". Chi ha ragione? La risposta dipende da cosa vuoi che accada nella tua collezione. Potrebbe non essere né a seconda di cosa stai cercando di fare.

Vedrai questo come un problema ancora e ancora. La cosa divertente è che c'è una soluzione ed è proprio accanto al Comparable. Gli oggetti che implementano Comparable hanno lo stesso enigma ma ora non solo devono determinare se sono uguali ma se sono più grandi di un altro oggetto. È davvero intrattabile al di fuori di un ambito di utilizzo molto ristretto. Quindi abbiamo quest'altra cosa chiamata Comparator. Il suo compito è guardare due oggetti e dire alla collezione quale è più grande. Tutti i problemi che stai cercando di fare nell'oggetto Comparable scompaiono.

Non conosco questo libro e non conosco l'autore, ma l'esempio con la birra non sembra affatto utile. Come fa la birra a sapere se dovrebbe essere in una bottiglia o in un barilotto e perché dovrebbe prendere quella decisione? Il suo compito è quello di avere un buon sapore e fornire alcol alla circolazione sanguigna degli utenti. Pensiamo davvero che i birrifici funzionino in questo modo? "Ok birra, dovresti essere in una bottiglia o in un barilotto e se è una bottiglia, dovrebbe essere una bottiglia da 25 once o una bottiglia da 12 once?" Qual è la birra in questo caso (nessun gioco di parole) comunque? È una goccia di birra? Forse questo è fuori dal contesto, ma penso che questo sia sbagliato o, perlomeno, non aggiunge alcuna illuminazione a questo concetto.

Detto questo, c'è un approccio alla costruzione di interfacce che ho usato che può semplificare le cose e renderlo più OO. In sostanza, si crea un'interfaccia che definisce le azioni astratte che è possibile eseguire per visualizzare l'oggetto. Potresti avere un'interfaccia chiamata Display metodi come setTitle o setDescription se stai usando lo schema di denominazione Java standard. Quindi il tuo oggetto avrebbe un metodo display(Display display) (perché il fascino è tre volte!) In questo approccio, l'oggetto non ha bisogno di capire quale sia l'interfaccia, potrebbe essere testo, binario, svg, bitmap, qualunque e il l'interfaccia non ha bisogno di sapere sull'oggetto. In questo modo un oggetto può "visualizzarsi" senza bisogno di sapere come funziona il display. Questo approccio può ridurre notevolmente il numero di classi wrapper necessarie ma può essere complicato se si hanno requisiti di visualizzazione complessi che variano in base all'oggetto. Puoi combinarlo con approcci di tipo MVC standard con buoni risultati.

    
risposta data 29.03.2016 - 19:24
fonte
8

Il principio di responsabilità singola non significa che una classe fa una sola cosa. Significa che una classe ha una sola ragione per cambiare.

Probabilmente stai pensando a un metodo , che in realtà fa solo una cosa.

Considerata la sua conclusione logica, la tua versione di SRP significherebbe che non saresti mai in grado di registrare nulla, perché la registrazione è una responsabilità separata.

È meglio pensare a una classe come a un singolo e ben definito soggetto . Puoi avere diversi metodi che supportano quell'argomento, e potrebbero tutti fare cose diverse.

Il metodo "display me" più fondamentale è ToString , che è sempre un metodo sull'oggetto.

Tutto ciò che è stato detto, quando creiamo un'interfaccia utente, in genere incoraggiamo Separazione delle preoccupazioni fornendo oggetti il cui unico scopo è la visualizzazione di dati da altri oggetti (ad esempio le viste).

Forse un esempio è in ordine. Considerare un sito Web PHP, utilizzando una vista. Una semplice vista potrebbe assomigliare a questa:

<?php
class View
{
    private $model;
    private $controller;

    public function __construct($controller,$model) {
        $this->controller = $controller;
        $this->model = $model;
    }

    public function output(){
        return "<p>" . $this->model->string . "</p>";
    }
}

In PHP, la vista contiene sempre una funzione output() . Per ottenere la rappresentazione visiva di una vista, tutto ciò che devi fare è chiamare output() , e otterrai una stringa adatta per la visualizzazione in qualsiasi browser moderno.

Se noterai che la View fa riferimento a un oggetto chiamato model . Questo è l'oggetto che contiene i dati effettivi. La vista e il modello sono in oggetti separati; questo è ciò che stabilisce la separazione delle preoccupazioni.

Separation of Concerns è importante per i siti web, perché è ciò che consente a un designer di lavorare su un design di pagina web diverso dal programmatore.

Ulteriori letture
Il pattern MVC e PHP

    
risposta data 29.03.2016 - 17:17
fonte
1

A giudicare dalle citazioni incollate, stai interpretando male il testo.

L'autore non sta dicendo che ogni oggetto dovrebbe essere in grado di presentarsi in un'interfaccia utente. Ciò sarebbe impossibile, dal momento che un oggetto non può sapere quale interfaccia grafica verrà mostrata in (in un'app WinForms, in un'app linux che utilizza XServer, come una stringa JSON, come XML, come un'immagine PNG ecc.)

Il punto sollevato è che dovresti scrivere punti di vista specializzati la cui unica responsabilità è quella di mostrare una certa entità. Ad esempio, potresti scrivere una vista che esegue il rendering di un oggetto come HTML (come avviene nelle viste nelle applicazioni MVC). È possibile creare un serializzatore JSON in grado di trasformare un oggetto in una stringa JSON. È possibile creare un oggetto che trasformi altri tipi di oggetti in report PDF. Tutto dipende.

Il punto è, separare l'entità aziendale dalla rappresentazione visiva (o serializzata). Sono cose diverse e cambiano per diversi motivi.

    
risposta data 29.03.2016 - 17:17
fonte

Leggi altre domande sui tag