2012-05-09 16 views
7

Je viens de sortir du collège et je rencontre un code où je dois réduire le couplage. Mais je ne comprends pas complètement tous les concepts et voudrais un exemple simple pour m'aider. Pour vous aider à démarrer, j'ai une classe de personne avec un seul champ, nom. J'ai une méthode dans cette classe pour concaténer du texte. Je sais que c'est un exemple idiot, et la plupart des gens n'envisageraient jamais de réduire le couplage dans des situations aussi simples, mais je veux seulement un exemple simple pour m'aider à comprendre le code et les concepts ensemble.Réduire le couplage simple exemple nécessaire pour le débutant

Dans le code derrière la fenêtre principale, j'ai mis une zone de texte, et un bouton. Lorsque la fenêtre est chargée, elle affiche la valeur actuelle du champ de nom de personne x. Lorsque vous cliquez sur le bouton, la méthode x.PersonAddText est appelée. Actuellement, cet exemple a un couplage calculé à 8. Avec un 3 pour l'événement de clic de bouton et un 3 pour l'événement chargé de la fenêtre.

Y at-il un moyen, en utilisant cet exemple, nous pouvons descendre à moins de cela pour l'un ou l'autre ou les deux.

Ci-dessous est tout mon code:

Ma personne 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) 
} 

Mon code Derrière:

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

My Simple 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> 

J'ai grande difficulté unde rstanding les tutoriels autour d'Internet expliquant cela. D'après ce que je vois, il y a 3 façons de le faire (ce serait bien si possible, d'avoir mon code ci-dessus converti en un exemple de trois):

  • Locator Service
  • injection de dépendances
  • Inversion de contrôle (IoC)

le article expliquant les choses que j'ai lu est excellent, mais les exemples ne sont pas pertinents pour moi qu'il utilise VB et ASP.Net avec des chaînes de connexion de base de données. C'est totalement à l'opposé de ce dont j'ai besoin, et je ne veux pas penser à la façon de traduire le code, tout en apprenant les concepts, et en pensant aussi à la façon de l'appliquer à quelque chose de pertinent. Alors que l'exemple est bon, c'est juste trop, et j'apprécierais vraiment toute aide supplémentaire.

Modifier Historique: Corrigé orthographes. J'ai ajouté ce qui suit pour clarifier ma question:

Je comprends la théorie derrière le couplage et la cohésion et pourquoi vous devriez réduire l'un et augmenter l'autre. Mais nous n'avons jamais eu à coder des exemples au collège. Aussi, bien que n'étant pas couvert à l'université, je comprends les interfaces. Cependant, je ne comprends pas comment les utiliser pour réduire le couplage.

Ajout d'un lien vers the article I refrenced above.

Edit 2: Jusqu'à présent, ce que j'ai maintenant obtenu est la suivante:

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

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

Comment puis-je utiliser maintenant ce dans le code mainwindow derrière?Je suppose que je devrais remplacer

Person x = new Person(); 

avec

IPerson x = new Person(); 

Est-ce exact, et si oui, est-il autre chose que je dois faire. La raison pour laquelle je demande est parce que je ne vois toujours aucune réduction dans les chiffres de couplage de code signalés par Visual Studio (en fait, il augmente de 1 sur le code de la fenêtre principale derrière).

+0

Qu'est-ce que _exactement_ ne comprenez-vous pas? Quel concept rencontrez-vous des difficultés? – Oded

+0

Je sais ce que signifie le coupeling et la cohésion en théorie. Mais je ne comprends pas comment le coder. Surtout que nous n'avons jamais couvert les interfaces au collège (oui, je sais, super collège). Je comprends aussi les interfaces, mais je ne sais pas comment les utiliser pour réduire le coupeling. –

Répondre

3

Modifier

Je suis heureux que ma réponse a aidé un peu, permettez-moi de le mettre à jour un peu plus loin. Pour utiliser votre question comme une réponse directe, tout ce que vous devez changer est votre déclaration sur le terrain à partir de:

Person x = new Person(); 

à

IPerson x = new Person(); 

Votre code-behind connaît maintenant les propriétés et méthodes qui sont spécifiées dans votre interface, et est beaucoup moins couplé, car vous pouvez échanger new Person() pour new Student() plus tard. Tant que l'objet implémente l'interface. Votre code-behind devrait maintenant fonctionner sans les changements nécessaires.

Side note

Je recommande considérant lazy-chargement de la personne x, et en utilisant également une propriété avec un nom plus reconnaissable. N.B. cela ne répond pas à votre question, mais c'est juste une suggestion. :)

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

De-couplage est lorsque deux, ou plus, les blocs de code ne doit pas dépendre de l'autre. Inversion of Control est lorsque le couplage des objets est lié à l'exécution, permettant ainsi beaucoup plus de flexibilité, et donc moins de couplage, des objets et de leurs instances. Inversion de contrôle est la meilleure utilisation en conjonction avec des interfaces. Les interfaces définissent que ClassA fera MethodX et auront PropertyY. Notre objet principal ne se soucie pas de savoir quel objet est retourné au moment de l'exécution, car log comme il peut remplir une interface, il est heureux.

Dans votre exemple ci-dessus, vous voulez interfacer votre classe de personne, peut-être quelque chose comme ceci:

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

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

Ensuite, dans vos appels principaux de la méthode, au lieu d'utiliser explicitement un objet Person, vous utiliserez un instance d'un objet qui implémente l'interface IPerson. L'accrochage de l'interface et de l'objet peut être réalisé par différentes bibliothèques qui vous aideront à configurer vos dépendances. Dans mon expérience, j'ai utilisé StructureMap et Microsoft's Enterprise Library. Ils peuvent être un peu Checklist pour mettre en place, mais une fois qu'ils sont, vous serez en mesure de faire quelque chose comme si ...

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

Je sais que ce ins't une réponse complète, mais nous espérons que ce J'aiderai un peu.:)

+0

Jusqu'à présent, cette réponse semble la plus facile à comprendre. Je suis en train de jouer avec et je reviendrai vers vous. Le seul problème que j'ai est que les liens que vous avez fournis entrent dans beaucoup de département assez rapidement et pour cet exemple simple, la compréhension est plus importante. Je vous accorderais la réponse si vous pouvez écrire le code nécessaire sans les extensions à la place de MainMethod_InInterfaceLayer().Peut-être en changeant ce que je devrais faire dans le code MainWindow derrière si possible. Merci pour votre aide jusqu'à maintenant. –

+1

J'ai mis à jour ma réponse. J'espère que, en conjonction avec la réponse de @ Oded, cela devrait être ce que vous cherchez. – Richard

+0

Merci Richard. J'applique juste votre réponse maintenant et l'explication derrière elle est très gentille. Je vais supposer que mon exemple est trop simple pour réduire la marque Visual Studio Coupling de 3 à 2 sur les méthodes mentionnées. Comme expliqué dans mes modifications, aucune réduction ne se produit lorsque je fais ce que vous avez décrit. Merci pour votre aide avec ceci. Je vais jouer avec votre note de côté aussi, mais j'ai le sentiment que c'est un peu sans rapport (bien que j'apprécie la suggestion). Je voudrais savoir le bienfait du chargement paresseux dans ce cas et quelle ligne d'enseignement vous a suggéré de le suggérer si vous avez le temps. –

2

que vous avez une interface IPerson et plusieurs application (Person, Student, Teacher etc) et vous avez un code qui doit simplement fonctionner sur un IPerson.

Ayant:

IPerson x = new Person(); 

dans votre code derrière fortement les couples à la classe Person.

L'inversion du contrôle entre en jeu en ayant les dépendances provenant de l'extérieur au lieu de créer l'intérieur de la classe.

Ceci est normalement réalisé en utilisant l'injection de dépendance - un IPerson étant passé dans la classe au lieu de la classe la créant directement. Vous pouvez le faire en passant une instance au constructeur (injection de constructeur) ou en tant que propriété (injection de propriété).

Le localisateur de service est un autre moyen d'obtenir des dépendances sans les coder en dur - le modèle "localise" une instance pour un type/une interface.

Un exemple de la façon d'injecter une dépendance à une 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

Laissez-moi d'abord vous remercier pour votre réponse. En utilisant le code dans richards, j'ai réussi à faire une interface jusqu'à présent. Le problème que j'ai maintenant est comment utiliser cela au lieu du code dans le code derrière. Ou est-ce ce que vous me montrez ci-dessus. Ce n'est pas très clair pour moi, mais si vous pouvez clarifier avec plus de code, je vais vous donner la réponse. Merci encore. –

+1

@FrancisRodgers - Ajout d'un exemple de la façon dont une classe 'MyClass' est découplée de toute implémentation de' IPerson', donc _any_ implémenteur peut être utilisé. Montrant également un cas d'injection de constructeur. – Oded

0

Supposons que vous ayez une classe de personne qui peut se charger de la base de données, se changer et envoyez un email quand il ou elle est morte.

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

Ce que vous pouvez voir ici est que cette personne fait réellement trois choses (au moins!).

Il sait comment parler à une base de données pour se charger. Il sait comment envoyer un email. Il peut changer lui-même.

Tout code, en théorie sinon pratique, ne devrait être responsable que d'une seule chose. Pour réduire le couplage entre ces composants, vous devez les séparer. Découpez-les pour qu'ils puissent travailler indépendamment.

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

Dans cet exemple, la personne n'a aucune idée de comment charger quelque chose à partir d'une base de données. Ignorer le fait que -loading- est quelque chose que vous devriez découpler aussi. L'envoi de courrier a également été découplé, puisque vous dites au Person.HaveDiedWillMail que vous voulez utiliser un mailer particulier (IMailer mailer).

Injection de dépendances, les conteneurs de service et une telle technologie trouvent automatiquement les composants dont votre personne a besoin pour fonctionner, une sorte de couche supplémentaire sur le découplage pour faciliter le câblage de toutes les pièces séparées.

+0

Je ne suis pas d'accord sur le fait qu'un objet (un modèle) devrait se charger de la base de données, même de manière faiblement couplée. Un modèle doit * faire une chose *: représenter un objet réel. Le chargement à partir de la base de données est le travail d'un autre objet, qui * fera une chose *: charger les données de la base de données. En fait, deux couches entre le modèle et la base de données seraient géniales. –

+0

Je suis d'accord avec vous aussi. Mais je n'essaie pas de tout expliquer ici ou même ce qui est sensé ... mais de découpler. – Jaapjan

Questions connexes