Una breve nota sobre los patrones de diseño: el principio de inversión de dependencia del principio de diseño

3.5 Principio de reversión de dependencia

3.5.1 Inversión de control (COI)

  • Inversión de control, abreviada como COI
public abstract class TestCase {
  public void run() {
    if (doTest()) {
      System.out.println("Test succeed.");
    } else {
      System.out.println("Test failed.");
    }
  }
  
  public abstract boolean doTest();
}

public class JunitApplication {
  private static final List<TestCase> testCases = new ArrayList<>();
  
  public static void register(TestCase testCase) {
    testCases.add(testCase);
  }
  
  public static final void main(String[] args) {
    for (TestCase case: testCases) {
      case.run();
    }
  }

Después de introducir esta versión simplificada del marco de prueba en el proyecto, solo necesita completar el código de prueba específico en el punto de extensión reservado por el marco, es decir, la función abstracta doTest () en la clase TestCase. No es necesario escribir la función main () responsable de ejecutar el proceso. El código específico es el siguiente:

public class UserServiceTest extends TestCase {
  @Override
  public boolean doTest() {
    // ... 
  }
}

// 注册操作还可以通过配置的方式来实现,不需要程序员显示调用register()
JunitApplication.register(new UserServiceTest();
  • Este es un ejemplo típico de implementación de "inversión de control" a través de un marco: el marco proporciona un esqueleto de código extensible para ensamblar objetos y administrar todo el proceso de ejecución. Cuando los programadores usan el marco para el desarrollo, solo necesitan agregar código relacionado con su propio negocio al punto de extensión reservado, y pueden usar el marco para impulsar la ejecución de todo el proceso del programa.

  • "Control" se refiere al control del flujo de ejecución del programa, y ​​"reverso" se refiere al control del programador sobre la ejecución de todo el programa antes de que se use el marco. Después de usar el marco, el marco puede controlar el flujo de ejecución de todo el programa. Control del proceso "invertido" del programador al framework.

  • La inversión de control no es una técnica de implementación específica, sino una idea de diseño más general, generalmente utilizada para guiar el diseño del nivel de marco.

3.5.2 Inyección de dependencia (DI)

  • Inyección de dependencia, abreviada como DI

  • Contrariamente a la reversión de control, es una técnica de codificación específica.

  • Para resumir en una oración: en lugar de crear un objeto de clase dependiente dentro de la clase a través de new (), pero después de crear el objeto de clase dependiente externamente, pasarlo (o inyectarlo) a la clase a través del constructor, parámetros de función, etc.

  • Ejemplo: la clase de notificación es responsable de enviar mensajes, y se basa en la clase MessageSender para enviar mensajes como promociones de productos y códigos de verificación a los usuarios. Use la inyección de dependencia y la inyección de no dependencia para lograr esto. El código de implementación específico es el siguiente:

    // 非依赖注入实现方式
    public class Notification {
      private MessageSender messageSender;
      
      public Notification() {
        this.messageSender = new MessageSender(); //此处有点像hardcode
      }
      
      public void sendMessage(String cellphone, String message) {
        //...省略校验逻辑等...
        this.messageSender.send(cellphone, message);
      }
    }
    
    public class MessageSender {
      public void send(String cellphone, String message) {
        //....
      }
    }
    // 使用Notification
    Notification notification = new Notification();
    
    // 依赖注入的实现方式
    public class Notification {
      private MessageSender messageSender;
      
      // 通过构造函数将messageSender传递进来
      public Notification(MessageSender messageSender) {
        this.messageSender = messageSender;
      }
      
      public void sendMessage(String cellphone, String message) {
        //...省略校验逻辑等...
        this.messageSender.send(cellphone, message);
      }
    }
    //使用Notification
    MessageSender messageSender = new MessageSender();
    Notification notification = new Notification(messageSender);
    

    Optimización:

    public class Notification {
      private MessageSender messageSender;
      
      public Notification(MessageSender messageSender) {
        this.messageSender = messageSender;
      }
      
      public void sendMessage(String cellphone, String message) {
        this.messageSender.send(cellphone, message);
      }
    }
    
    public interface MessageSender {
      void send(String cellphone, String message);
    }
    
    // 短信发送类
    public class SmsSender implements MessageSender {
      @Override
      public void send(String cellphone, String message) {
        //....
      }
    }
    
    // 站内信发送类
    public class InboxSender implements MessageSender {
      @Override
      public void send(String cellphone, String message) {
        //....
      }
    }
    
    //使用Notification
    MessageSender messageSender = new SmsSender();
    Notification notification = new Notification(messageSender);
    

    En lo anterior, los objetos de clase dependiente se pasan a través de la inyección de dependencia, que puede reemplazar de manera flexible las clases dependientes y mejorar la escalabilidad del código .

3.5.3 Marco de inyección de dependencia (marco DI)

  • Existen muchos marcos de inyección de dependencias, como Google Guice, Java Spring, Pico Container, Butterfly Container, etc.
  • Solo necesita configurar todos los objetos de clase que deben crearse, las dependencias entre clases y clases a través de los puntos de extensión proporcionados por el marco de inyección de dependencia, y puede implementar el marco para crear objetos automáticamente, administrar el ciclo de vida de los objetos y la inyección de dependencia Cosas que necesitan que hagan los programadores.

3.5.4 Principio de inversión de dependencia (DIP)

  • Principio de inversión de dependencia, abreviado como DIP

  • Los módulos de alto nivel no dependen de los módulos de bajo nivel. Los módulos de alto nivel y los módulos de bajo nivel deben depender unos de otros a través de abstracciones.

  • La abstracción (abstracciones) no se basa en detalles específicos de implementación (detalles), los detalles específicos de implementación (detalles) dependen de la abstracción (abstracciones).

  • La división de módulos de alto nivel y módulos de bajo nivel es simplemente que, en la cadena de llamadas, la persona que llama pertenece al nivel alto y la persona que llama pertenece al nivel bajo.

  • Ejemplo: Tomcat es un contenedor para ejecutar aplicaciones web Java. El código de la aplicación web que escribimos solo debe implementarse bajo el contenedor Tomcat, y luego puede ser llamado y ejecutado por el contenedor Tomcat. De acuerdo con el principio de división anterior, Tomcat es un módulo de alto nivel, y el código de la aplicación web que escribimos es un módulo de bajo nivel. No existe una dependencia directa entre Tomcat y el código de la aplicación. Ambos se basan en la misma "abstracción", que es la especificación de Servlet. La especificación de Servlet no depende de los detalles de implementación de contenedores y aplicaciones de Tomcat específicos, mientras que el contenedor y las aplicaciones de Tomcat dependen de la especificación de Servlet.

3.5.5 opiniones

  • SmallFly:

    El concepto del principio de inversión de dependencia es que los módulos de alto nivel no dependen de módulos de bajo nivel. Parece que se requieren módulos de alto nivel, pero en realidad está regulando el diseño de módulos de bajo nivel.

    La interfaz proporcionada por el módulo de bajo nivel debe ser lo suficientemente abstracta y general, y el tipo de uso y el escenario del módulo de alto nivel deben considerarse en el diseño .

    Obviamente, el módulo de alto nivel debe usar el módulo de bajo nivel y depender del módulo de bajo nivel. Por el contrario, los módulos de bajo nivel deben diseñarse de acuerdo con los módulos de alto nivel, y aparece la apariencia de "invertido" .

    Este diseño tiene dos ventajas:

    1. Los módulos de bajo nivel son más versátiles y más aplicables.
    2. El módulo de alto nivel no depende de la implementación específica del módulo de bajo nivel, lo que facilita la sustitución del módulo de bajo nivel.

Supongo que te gusta

Origin www.cnblogs.com/wod-Y/p/12746794.html
Recomendado
Clasificación