2012-05-09 17 views
7

Acabo de salir de la universidad y me encuentro con algún código donde necesito reducir el acoplamiento. Pero no entiendo completamente todos los conceptos y me gustaría un simple ejemplo para ayudarme. Para empezar, tengo una clase de persona con un solo campo, nombre. Tengo un método dentro de esa clase para concatenar algún texto.Acoplamiento reductor ejemplo simple necesario para principiante

Sé que este es un ejemplo tonto, y la mayoría de las personas nunca considerarían reducir el acoplamiento en situaciones tan simples como esta, pero solo quiero un ejemplo simple que me ayude a comprender completamente el código y los conceptos.

En el código detrás de la ventana principal pongo un cuadro de texto y un botón. Cuando la ventana se carga, muestra el valor actual del campo persona x nombre. Cuando se hace clic en el botón, se llama al método x.PersonAddText. Actualmente, este ejemplo tiene un acoplamiento calculado en 8. Con un 3 para el evento de clic de botón y un 3 para el evento de ventana cargada.

¿Hay alguna manera, utilizando este ejemplo podemos bajarlo a menos de esto para uno o ambos?

continuación es todo mi código:

Mi persona Clase:

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

Mi código subyacente:

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

Mi XAML simple:

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

estoy teniendo gran dificultad unde Comprender los tutoriales en Internet explicando esto. Por lo que veo hay 3 formas de hacer esto (que sería bueno si es posible, tener mi código convertido a un ejemplo de los tres):

  • Servicio de Localización de
  • inyección de dependencias
  • Inversion del control (COI)

el article explicar las cosas que he leído es excelente, pero los ejemplos no son relevantes para mí como él está utilizando VB y ASP.Net con cadenas de conexión de base de datos. Esto es totalmente contrario a lo que necesito, y no quiero pensar en cómo traducir el código, al mismo tiempo que aprendo los conceptos, y también pienso en cómo aplicarlo a algo relevante. Si bien el ejemplo es bueno, es demasiado, y realmente agradecería cualquier ayuda adicional.

Editar historial: deletreos corregidos. Agregué lo siguiente para aclarar mi pregunta:

Entiendo la teoría detrás del acoplamiento y la coherencia y por qué debería reducir una y aumentar la otra. Pero nunca tuvimos que codificar ningún ejemplo en la universidad. Además, aunque no estoy cubierto en la universidad, entiendo las interfaces. Sin embargo, no entiendo cómo usarlos para reducir el acoplamiento.

Agregó un enlace a the article I refrenced above.

Edición 2: Hasta ahora lo que ahora tengo es la siguiente:

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

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

¿Cómo utilizar ahora esta en el código MainWindow atrás?Estoy adivinando que debería sustituir a

Person x = new Person(); 

con

IPerson x = new Person(); 

Es esto correcto, y si es así, ¿hay algo más que tenga que hacer. La razón por la que pregunto es porque todavía no veo ninguna reducción en las cifras de acoplamiento de código informadas por Visual Studio (de hecho, lo aumenta en 1 en el código de la ventana principal).

+0

¿Qué _exactly_ no lo entiendes? ¿Con qué concepto estás teniendo problemas? – Oded

+0

Sé lo que significa coupeling y cohesión en teoría. Pero no entiendo cómo codificarlo. Especialmente porque nunca cubrimos interfaces en la universidad (sí, lo sé, excelente universidad). También entiendo las interfaces, pero no sé cómo usarlas para reducir el coupeling. –

Respuesta

3

Editar

Me alegro de que mi respuesta ayudó un poco, vamos a actualizar es un poco más. Para utilizar su pregunta como una respuesta directa, todo lo que se tenga que cambiar es su declaración de campo de:

Person x = new Person(); 

a

IPerson x = new Person(); 

Su código subyacente ahora sabemos las propiedades y métodos que se especifican en su interfaz, y está mucho menos acoplado, ya que podría cambiar new Person() por new Student() más adelante. Mientras el objeto implemente la interfaz. Su código subyacente ahora debería funcionar sin ningún cambio necesario.

Nota al margen

recomendaría teniendo en cuenta la persona x, y también el uso de una propiedad con un nombre más reconocible-carga diferida. nótese bien esto no responde su pregunta, pero es solo una sugerencia. :)

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

De-acoplamiento es cuando dos o más, los bloques de código no debería depender unos de otros. La inversión del control se produce cuando el acoplamiento de los objetos está ligado en el tiempo de ejecución, lo que permite mucha más flexibilidad y, por lo tanto, menos acoplamiento de los objetos y sus instancias. La inversión del control es el mejor uso junto con las interfaces. Las interfaces definen que ClassA hará MethodX y tendrá PropertyY. A nuestro objeto principal no le importa qué objeto se devuelve en el tiempo de ejecución, ya que el registro puede cumplir una interfaz, es feliz.

En el ejemplo anterior, tendrá que interconectar su clase de persona, tal vez algo así:

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

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

Entonces, dentro de sus principales llamadas de método, en lugar de utilizar de forma explícita un objeto Person, que va a utilizar una instancia de un objeto que implementa la interfaz IPerson. El "enganche" de la interfaz y el objeto se puede lograr mediante diferentes bibliotecas que ayudarán a configurar sus dependencias. En mi experiencia, he usado StructureMap y Microsoft's Enterprise Library. Ellos pueden ser un poco complicados de configurar, pero una vez que son, usted será capaz de hacer algo así ...

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

Sé que esto ins't una respuesta completa, pero con suerte' Ayudaré un poco.:)

+0

Hasta ahora, esta respuesta parece ser la más fácil de entender. Actualmente estoy jugando con eso y me pondré en contacto contigo. El único problema que tengo es que los enlaces que proporcionaste entran en un departamento con bastante rapidez y para este simple ejemplo, la comprensión es más importante. Le otorgaría la respuesta si puede escribir el código necesario sin las extensiones en lugar de MainMethod_InInterfaceLayer().Tal vez cambiando lo que debería hacer en el código MainWindow detrás si es posible. Gracias por su ayuda hasta ahora. –

+1

He actualizado mi respuesta. Con suerte, en conjunto con la respuesta de @Oded, debería ser lo que estás buscando. – Richard

+0

Gracias Richard. Solo estoy implementando tu respuesta ahora y la explicación detrás es muy buena. Voy a suponer que mi ejemplo es demasiado simple para reducir la marca de Acoplamiento Visual Studios de 3 a 2 en los métodos mencionados. Como se explica en mis ediciones, no ocurre ninguna reducción cuando hago lo que usted describió. Gracias por ayudarme con esto. Jugaré con su nota lateral también, pero tengo la sensación de que esto no está relacionado (aunque aprecio la sugerencia). Me gustaría saber el beneficio de la carga perezosa en este caso y qué línea de enseñanza te enseñó a sugerirlo si tienes tiempo. –

2

Digamos que tiene una interfaz IPerson y varios aplicación (Person, Student, Teacher etc) y usted tiene un código que simplemente tiene que operar en una IPerson.

Tener:

IPerson x = new Person(); 

en su código detrás de las parejas fuertemente a la clase Person.

La inversión de control entra en juego al tener las dependencias provenientes del exterior en lugar de crear el interior de la clase.

Esto normalmente se logra mediante el uso de la inyección de dependencia: se pasa un IPerson a la clase en lugar de la clase que lo crea directamente. Puede hacerlo pasando una instancia al constructor (inyección de constructor) o como una propiedad (inyección de propiedad).

El localizador de servicios es otra forma de obtener dependencias sin una codificación rigurosa: el patrón "localiza" una instancia para un tipo/interfaz.

Un ejemplo de cómo inyectar una dependencia a una clase:

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

Primero permítame darle las gracias por su respuesta. Usando el código en la respuesta de Richards, pude hacer una interfaz hasta el momento. El problema que ahora tengo es cómo usar eso en lugar del código en el código. O es eso lo que me estás mostrando arriba. No es del todo claro para mí, pero si puede aclarar con más código, le daré la respuesta. Gracias de nuevo. –

+1

@FrancisRodgers: se agregó un ejemplo de cómo una clase 'MyClass' está desacoplada de cualquier implementación de' IPerson', por lo que se puede usar cualquier implementador. También muestra un caso de inyección de constructor. – Oded

0

Suponga que tiene una clase de persona que puede cargarse a partir de la base de datos, cambiarnos y enviar correo electrónico cuando él o ella murió.

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

Lo que se ve aquí es que esta persona está haciendo en realidad tres cosas (al menos!).

Sabe cómo hablar con una base de datos para cargarse. Sabe cómo enviar correos electrónicos. Puede cambiar solo.

Cualquier código, en teoría si no se practica, debería ser responsable de una sola cosa. Para reducir el acoplamiento entre estos componentes, debe separarlos. Desacoplarlos para que puedan trabajar de forma independiente.

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

En este ejemplo ideado, la persona no tiene idea de cómo cargar algo de una base de datos. Ignorando el hecho de que "cargar" es algo que también debes desacoplar. También se ha desacoplado el envío de correo, ya que le dice al Person.HaveDiedWillMail que desea utilizar un correo particular (IMailer mailer).

Inyección de dependencia, los contenedores de servicio y esa tecnología encuentran automáticamente los componentes que su Persona necesita/quiere para funcionar, una especie de capa adicional sobre el desacoplamiento para facilitar el cableado de todas las partes separadas.

+0

No estoy de acuerdo en que un objeto (un modelo) se cargue a sí mismo de la base de datos, incluso de una manera débilmente acoplada. Un modelo debe * hacer una cosa *: representar un objeto real. Cargar desde la base de datos es el trabajo de otro objeto, que * hará una cosa *: cargar datos de la base de datos. De hecho, dos capas entre el modelo y la base de datos serían geniales. –

+0

Estoy de acuerdo con usted también. Pero no estoy tratando de explicar todo aquí o incluso lo que es sensato ... sino desacoplamiento. – Jaapjan