2009-03-27 5 views
7

Mantenere le classi vagamente accoppiate è un aspetto importante della scrittura di codice che è facile da capire, modificare e eseguire il debug. Come novizio, però, quasi ogni volta che vado oltre gli esempi più semplici, faccio fatica.Loose Coupling e OO Practices per principianti

Capisco, più o meno, come posso incapsulare stringhe, numeri interi e tipi di dati semplici in classi proprie. Quando inizio ad occuparmi di informazioni come la formattazione di rich text, tuttavia, le cose si complicano molto - a meno che non utilizzi solo i vari metodi già presenti in un componente. Per continuare questo esempio, supponiamo che stavo scrivendo qualcosa che includeva un componente memo RTF nell'interfaccia utente. In Delphi, il componente ha metodi integrati per fare cose come salvare il testo formattato. Inoltre, a volte sembra che l'unico (o almeno il migliore) modo di lavorare con il testo RTF sia tramite metodi ancora incorporati nel componente.

Come (o perché) dovrei fare tutto il lavoro di salvataggio, caricamento e formattazione del testo in un'altra classe quando ho già un componente che fa tutto questo per me?

Da solo, di solito finisco per (a) fare qualcosa che sembra molto più complicato del necessario, reinventare metodi già presenti, o (b) creare classi scarsamente fatte che sono ancora strettamente accoppiate l'una con l'altra. Come si dice nell'informatica, "ci deve essere un modo migliore!"

Sono semplicemente perso concettualmente su come quella "via migliore" funzioni. qualche idea?

risposta

5

Credo che tu abbia perso su alcuni concetti di base.

L'idea alla base di OOP inizia con unità di logica discrete e riutilizzabili. Con l'accento sulla creazione di moduli autosufficienti.

Nel caso del componente Memo RTF, soddisfa i criteri di cui sopra gestendo un determinato set di dati (il memo) in modo tale che il programma e gli altri oggetti all'interno del programma non si preoccupino di come lo fa lavoro. Lo scopo è mostrare un'interfaccia, accettare i dati, manipolare i dati specifici e trasmettere tali dati a un'altra parte del programma.

L'idea di loosely coupled è semplicemente quella di poter sostituire quel controllo di promemoria con un altro controllo che soddisfa le stesse specifiche di interfaccia. In particolare, è possibile creare un'istanza, consentire all'utente di interagire con esso e estrarre i dati quando necessario.

Essere accoppiato liberamente va di pari passo con l'idea di Separation of Concerns (SoC); che è il processo di rompere un programma in funzionalità distinte al fine di ridurre la sovrapposizione di funzionalità e renderne più facile la gestione. Ma non sono la stessa cosa Incidentalmente, questo è stato anche uno dei principali fattori alla base del passaggio dallo stile procedurale di programmazione a OOP. Come OOP costringe la programmazione a pensare in termini di funzionalità correlate e discrete.

Sembra che tu stia davvero chiedendo di SoC.

Ci sono molti modi per ottenere SoC. A volte ciò comporta la separazione dell'interfaccia utente, della logica di elaborazione e dei livelli di persistenza (ad esempio, considerare il modello di progettazione MVC). A volte si tratta semplicemente di mantenere insieme le funzioni correlate al fine di ridurre la complessità; che il controllo RTF già esegue contenendo tutte le funzioni necessarie per manipolare i dati in modo da non avere ulteriori dipendenze.

0

Bene, non sono completamente chiaro sulla domanda, ma sembra quasi che lo schema strategico funzioni qui.

Creare un oggetto basato sull'oggetto RTF principale ma impostare i metodi di gestione per la memorizzazione, ecc. Come oggetti definiti con i propri metodi.

Ciò abilita la potenza della composizione senza ereditare strettamente tutti i metodi padre e non è necessario creare un enorme oggetto personalizzato, basta sostituire i metodi necessari.

5

Vorrei suggerire due concetti, interfacce e iniezione di dipendenza, come un modo per disaccoppiare le classi. Le interfacce consentono di definire un contratto o un insieme di comportamenti previsti indipendenti da qualsiasi implementazione. Quando una classe si basa su un'interfaccia anziché su una classe, si ha la libertà di sostituire altre classi che implementano l'interfaccia senza dover riscrivere la classe che dipende da essa.

Quando si utilizzano le interfacce con l'integrazione delle dipendenze, ossia, fornire alla classe l'implementazione effettiva su cui deve essere eseguito piuttosto che creare un'implementazione particolare, si ottiene un ulteriore disaccoppiamento nell'applicazione. Ora la classe conosce solo l'interfaccia e non sa nemmeno come crearla, basta usarla. L'iniezione di dipendenza viene spesso utilizzata con modelli di creazione come Builder o Factory, in cui si localizza la costruzione di oggetti in una singola classe in modo che solo quella classe debba essere modificata quando si estende l'applicazione con classi aggiuntive.

Inoltre, ricorda che l'accoppiamento (e il suo gemello, la coesione) è una misura relativa. Non puoi eliminare tutto l'accoppiamento o i tuoi oggetti non sarebbero in grado di interagire. È necessario avere un certo livello di dipendenza. È necessario bilanciarlo con facilità d'uso e implementazione.

Per quanto riguarda il vostro esempio particolare, è difficile dire senza codice effettivo. Sospetto che tu stia sovra-ingegnerizzando la soluzione e violando il principio di ASCIUTTO (non ripeterti). Potrebbe essere necessario esaminare i modi per utilizzare le interfacce e forse un involucro leggero per separare le classi dal componente quadro piuttosto che una completa reimplementazione.

+0

No, in Delphi è molto più probabile che l'ingegnere non funzioni –

0

L'esempio che hai scelto è piuttosto complesso.

Hai ragione quando dici che il componente rtf memo è accoppiato molto liberamente. Quindi, in modo approssimativo, che non è praticamente estensibile e può essere utilizzato solo così com'è, poiché integra presentazione/vista, controller e modello.

Se si desidera visualizzare un esempio di un sistema RTF ben progettato ed estensibile, consultare la documentazione dello OS X text system (o di Gnustep, se si desidera leggere il codice). È complesso, perché ci sono molte decisioni progettuali che devono essere fatte e devono essere nascoste da un modulo all'altro. Lì puoi lavorare direttamente in una buona struttura.

Il componente memo rtf ha una portata limitata di utilizzo, che potrebbe essere necessario risolvere utilizzando le classi ben progettato:

  • Il caricamento e il salvataggio dei dati di componenti senso solo se non lo fai salvare altri dati nel programma nello stesso file/db.
  • Inoltre, non gestisce bene grandi quantità di dati.
  • E comprende solo un piccolo sottoinsieme di rtf.