2012-05-09 15 views
7

Appena usciti dal college mi sto imbattendo in un codice in cui ho bisogno di ridurre l'accoppiamento. Ma non capisco pienamente tutti i concetti e vorrei un semplice esempio per aiutarmi. Per iniziare ho una classe di persona con un singolo campo, nome. Ho un metodo all'interno di quella classe per concatenare del testo.Riduzione del semplice esempio di accoppiamento per principianti

So che questo è un esempio stupido e la maggior parte delle persone non prenderebbe mai in considerazione la possibilità di ridurre l'accoppiamento in situazioni così semplici, ma desidero solo un semplice esempio per aiutarmi a comprendere appieno il codice ei concetti insieme.

Nel codice dietro la finestra principale ho inserito una casella di testo e un pulsante. Quando la finestra viene caricata mostra il valore corrente del campo x persona del nome. Quando si fa clic sul pulsante, viene chiamato il metodo x.PersonAddText. Attualmente questo esempio ha l'accoppiamento calcolato a 8. Con un 3 per l'evento click del pulsante e un 3 per l'evento caricato in finestra.

C'è un modo, utilizzando questo esempio possiamo ridurlo a meno di questo per entrambi o entrambi.

Qui di seguito è tutto il mio codice:

La mia persona Classe:

public class Person 
{ 
    //Fields 
    private string name; 

    //Properties 
    public string Name 
    { 
     get { return name; } 
     set { name = value; } 
    } 

    //Constructors 
    public Person() 
    { 
     name = "joe"; 
    } 

    //Methods 
    public string PersonAddText(string text) 
    { 
     return name += " - " + text; 
    } 

    //Interfaces (or additional code below here please to aid understanding) 
} 

My Code Dietro:

Person x = new Person(); 

    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     txtname.Text = x.Name; 
    } 

    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     txtname.Text = x.PersonAddText(txtname.Text); 
     txtname.Text = x.Name; 
    } 

mio semplice XAML:

<Grid> 
    <TextBox Name="txtname" Margin="12,12,12,0" Height="23" VerticalAlignment="Top" /> 
    <Button Content="Add Text" Margin="12,41,12,0" Name="button1" VerticalAlignment="Top" Click="button1_Click" /> 
</Grid> 

Sto avendo grande difficoltà unde sostenere i tutorial su internet spiegando questo. Da quello che vedo ci sono 3 modi per fare questo (sarebbe bello, se possibile, di avere il mio codice di cui sopra convertito in un esempio di tutti e tre):

  • Service Locator
  • Dependency Injection
  • Inversion del controllo (IOC)

il article spiegare le cose che ho letto è eccellente, ma gli esempi non sono rilevanti per me come lui sta usando VB e ASP.Net con le stringhe di connessione al database. Questo è totalmente opposto a quello di cui ho bisogno, e non voglio pensare a come tradurre il codice, imparando i concetti e pensando anche a come applicarlo a qualcosa di rilevante. Mentre l'esempio è buono, è davvero troppo, e apprezzerei davvero ogni ulteriore aiuto.

Cronologia delle modifiche: Correggere le ortografie. Aggiunto il seguente per chiarire la mia domanda:

Capisco la teoria dietro l'accoppiamento e la coheasion e perché si dovrebbe ridurre uno e aumentare l'altro. Ma non abbiamo mai potuto codificare alcun esempio al college. Inoltre, mentre non sono al college, comprendo le interfacce. Tuttavia, non capisco come usarli per ridurre l'accoppiamento.

Aggiunto un collegamento a the article I refrenced above.

Edit 2: Finora quello che ho ora ottenuto è la seguente:

public interface IPerson 
{ 
    string Name { get; set; } 
    string PersonAddText(string text); 
} 

public class Person : IPerson 
{ 
    //The code from the person class above 
} 

Come faccio ora utilizzare questo nel codice MainWindow dietro?Sto indovinando che dovrei sostituire

Person x = new Person(); 

con

IPerson x = new Person(); 

E 'corretto, e se è così, c'è qualcos'altro che devo fare. Il motivo per cui lo chiedo è perché non vedo ancora alcuna riduzione delle figure di accoppiamento del codice riportate da Visual Studio (infatti, aumenta di 1 il codice della finestra principale dietro).

+0

Che cosa esattamente non capisci? Con quale concetto hai difficoltà? – Oded

+0

So che cosa significa coupeling e coesione in teoria. Ma non capisco come codificarlo. Soprattutto perché non abbiamo mai parlato di interfacce al college (sì, lo so, ottimo college). Capisco anche le interfacce, ma non so come usarle per ridurre il coupeling. –

risposta

3

Modifica

Sono contento la mia risposta ha aiutato un po ', mi permetta di aggiornare è un po' più. Per utilizzare la tua domanda come una risposta diretta, tutto quello che avrebbe bisogno di cambiare è la vostra dichiarazione di campo da:

Person x = new Person(); 

a

IPerson x = new Person(); 

code-behind ora sappiamo le proprietà ei metodi specificati nel la tua interfaccia, ed è molto meno accoppiata, dato che potresti sostituire lo new Person() per new Student() in seguito. Finché l'oggetto implementa l'interfaccia. Il code-behind dovrebbe ora funzionare senza modifiche necessarie.

Nota a margine

Suggerirei considerando pigro-caricamento del x persona, e anche utilizzando una proprietà con un nome più riconoscibile. N.B. questo non risponde alla tua domanda, ma è solo un suggerimento. :)

private IPerson _CurrentPerson = null; 
private IPerson CurrentPerson 
{ 
    get 
    { 
     if (this._CurrentPerson == null) 
     { 
      this._CurrentPerson = new Person(); 
     } 
     return this._CurrentPerson 
    } 
    set 
    { 
     this._CurrentPerson = value; 
    } 
} 

De-accoppiamento è quando due o più, blocchi di codice non dovrebbe dipendere vicenda. Inversion of Control è quando l'accoppiamento di oggetti è vincolato in fase di runtime, consentendo così una maggiore flessibilità, e quindi minore accoppiamento, degli oggetti e delle loro istanze. L'inversione del controllo è l'uso migliore in combinazione con le interfacce. Le interfacce definiscono che ClassA farà MethodX e hanno PropertyY. Il nostro oggetto principale non si preoccupa di quale oggetto viene restituito in fase di esecuzione, come log in quanto può soddisfare un'interfaccia, è felice.

Nel tuo esempio sopra, si vuole interfacciare la classe persona, forse qualcosa in questo modo:

public interface IPerson 
{ 
    string Name { get; set; } 
    string PersonAddText(string text); 
} 

public class Person : IPerson 
{ 
    // your code here 
} 

Poi, all'interno delle vostre chiamate di metodo principale, invece di in modo esplicito utilizzando un oggetto Person, si utilizzerà un istanza di un oggetto che implementa l'interfaccia IPerson. Il "collegamento" dell'interfaccia e dell'oggetto può essere ottenuto da varie librerie diverse che aiuteranno nell'impostazione delle dipendenze. Nella mia esperienza ho usato StructureMap e Microsoft's Enterprise Library. Essi possono essere un po 'poco pratici per set-up, ma una volta che sono, sarete in grado di fare qualcosa di simile in modo ...

public void MainMethod_InInterfaceLayer() 
{ 
    // container is an instance of UnityContainer 
    Person newPerson = container.Resolve<IPerson>(); 
} 

So che questa ins't una risposta completa, ma si spera che' Ti aiuterò un po '.:)

+0

Finora questa risposta sembra la più facile da capire. Attualmente sto giocando con esso e tornerò da te. L'unico problema che sto avendo è che i collegamenti che hai fornito entrano in molto tempo molto rapidamente e per questo semplice esempio, la comprensione è più importante. Ti assegnerei la risposta se riuscissi a scrivere il codice necessario senza le estensioni invece del MainMethod_InInterfaceLayer().Forse cambiando ciò che dovrei fare nel codice MainWindow, se possibile. Grazie per il tuo aiuto finora. –

+1

Ho aggiornato la mia risposta. Speriamo che, in congiunzione con la risposta di @ Oded, dovrebbe essere quello che stai cercando. – Richard

+0

Grazie Richard. Sto solo implementando la tua risposta ora e la spiegazione dietro è molto bella. Presumo che il mio esempio sia troppo semplice per ridurre il marchio Coupling di Visual Studio da 3 a 2 sui metodi menzionati. Come spiegato nelle mie modifiche, nessuna riduzione accade quando faccio come hai descritto. Grazie per il tuo aiuto con questo. Suonerò anche con la tua nota a margine, ma ho la sensazione che questo sia in qualche modo non correlato (anche se apprezzo il suggerimento). Mi piacerebbe conoscere il vantaggio del caricamento pigro in questo caso e quale linea di insegnamento ti ha insegnato a suggerire se hai tempo. –

2

Diciamo che avere un'interfaccia IPerson e diversi implementazione (Person, Student, Teacher ecc) e si ha un codice che ha bisogno semplicemente di operare su un IPerson.

Avere:

IPerson x = new Person(); 

nel codice dietro con forza le coppie alla classe Person.

L'inversione di controllo entra in gioco facendo sì che le dipendenze provengano dall'esterno anziché creare l'interno della classe.

Questo è normalmente ottenuto utilizzando l'iniezione di dipendenza: un IPerson viene passato nella classe invece della classe che lo crea direttamente. È possibile farlo passando un'istanza al costruttore (iniezione costruttore) o come proprietà (proprietà di iniezione).

Il localizzatore di servizio è un altro modo per ottenere le dipendenze senza doverli codificare con difficoltà: il modello "individua" un'istanza per un tipo/interfaccia.

Un esempio di come iniettare una dipendenza a una classe:

public class MyClass 
{ 
    IPerson person; 

    public MyClass(IPerson p) 
    { 
    person = p; // injected an instance of IPerson to MyClass 
    } 

    // can now use person in any method of the class, or pass it around: 

    public void MyMethod() 
    { 
    string name = person.Name; 
    } 
} 
+0

Prima lascia che ti ringrazi per la risposta. Usando il codice nella risposta di Richards, sono riuscito a creare un'interfaccia finora. Il problema che sto avendo ora è come usare quello invece del codice nel codice sottostante. O è quello che mi stai mostrando sopra. Non è abbastanza chiaro per me, ma se puoi chiarire con più codice, ti assegnerò la risposta. Grazie ancora. –

+1

@FrancisRodgers - Aggiunto un esempio di come una classe 'MyClass' è disaccoppiata da qualsiasi implementazione di' IPerson', quindi _any_ implementer può essere usato. Mostra anche un caso di iniezione del costruttore. – Oded

0

Supponiamo di avere una classe Persona che si può caricare dal database, ottenere cambiato e invia un'email quando lui o lei è morta.

class Person 
{ 
    ... 
    void LoadUsingId(int id); 
    void HaveDiedWillMail(); 
    void SetFirstName(string name); 
    ... 
} 

Che cosa si può vedere qui è che questa persona sta effettivamente facendo tre cose (per lo meno!).

Sa come comunicare con un database per caricarsi. Sa come inviare e-mail. Può cambiare se stesso.

Qualsiasi codice, in teoria se non pratico, dovrebbe essere responsabile di una sola cosa. Per ridurre l'accoppiamento tra questi componenti, è necessario separarli. Disaccoppiateli in modo che possano lavorare indipendentemente.

class Person 
{ 
    ... 
    void LoadUsingId(PersonRepository person); 
    void HaveDiedWillMail(IMailer mailer); 
    void SetFirstName(string name); 
    ... 
} 

In questo esempio forzato, la Persona non ha idea di come caricare qualcosa da un database. Ignorare il fatto che -caricare- è qualcosa che dovresti anche disaccoppiare. Anche l'invio di posta è stato disaccoppiato, dal momento che tu dici allo Person.HaveDiedWillMail di voler usare un particolare mailer (IMailer mailer).

Iniezione di dipendenza, contenitori di servizio e tale tecnologia individuano automaticamente i componenti di cui la persona ha bisogno/desidera per funzionare, una sorta di strato aggiuntivo sopra il disaccoppiamento per semplificare il cablaggio di tutte le parti separate.

+0

Non sono d'accordo sul fatto che un oggetto (un modello) debba caricarsi dal database, anche in un modo poco accoppiato. Un modello dovrebbe * fare una cosa *: rappresentare un oggetto reale. Il caricamento dal database è il lavoro di un altro oggetto, che * farà una cosa *: carica i dati dal database. In effetti, due strati tra il modello e il database sarebbero fantastici. –

+0

Sono d'accordo anche con te. Ma non sto cercando di spiegare tutto qui o anche ciò che è sensato ... ma disaccoppiare. – Jaapjan