【问题标题】:Programming to an interface instead of an implementation: Why is assigning the concrete implementation of an object at runtime even better?对接口而不是实现进行编程:为什么在运行时分配对象的具体实现会更好?
【发布时间】:2013-10-08 09:08:12
【问题描述】:

在 Head First Design Patterns 中,有人提到您应该编写接口而不是实现,但是代码示例的最后一部分让我感到困惑。如何在运行时分配对象的具体实现是一个更好的设计?

这是否意味着将对象的实例化放在使用超类型的类的方法中更好? (一种专门将对象返回给超类的变量的方法)

//Programming to an implementation would be:
Dog d = new Dog();
d.bark();

//Programming to an interface/supertype would be:
Animal animal = new Dog();
animal.makeSound();

//Even better is assigning the concrete implementation at runtime: (says the book)
a = getAnimal();
animal.makeSound();

【问题讨论】:

标签: java design-patterns runtime


【解决方案1】:

更好的方法是让其他人根据代码执行的环境/上下文来计算具体的类。这称为控制反转/依赖注入,其中实际类要么在某些配置文件中配置,要么使用约定编码来识别正确的文件。

回到原因,想象一个中等复杂性的项目,您必须与 DB 交谈。如果您硬编码访问数据库的方式,您最终会要求客户坚持使用特定类型/版本的数据库。这就是 JDBC 的工作原理。同样对于更复杂的场景,想象一下从基于 Db 的系统文件转移。一旦您获得了该软件的设计灵活性,就很容易理解具体类的延迟初始化。

【讨论】:

  • 你好,我有同样的问题希望你能用一个具体的例子来澄清,更具体地说,如何在 a = getAnimal(); 中实现函数 getAnimal a.makeSound()?如何调用 getAnimal (没有对象也没有静态类)?这个函数会包含一个类的构造函数吗?
  • 通过这种方法,您可以完全从 A 中删除 Animal 的依赖。因此,您的代码可以存在于不同的 repos 中,并且完全不同的团队可以在模块 A 上工作(松散地使用而不是 project/jar ) 和模块 Animal 甚至不知道 Animal 将在运行时使用。然后,您可以使用类 DifferentAnimal 创建第三个模块,并使用它来注入而不是 Animal。
  • 哇! Stackoverflow 的评论太糟糕了。这是使用 Spring 框架的代码示例。美妙之处在于您无需担心 getAnimal() 方法——这现在是依赖注入框架的工作。 Spring 和 Guice 是 Java 类 A 中两个最大的 DI 框架 { @Autowired private BeingAnimal a; public void someMethod() { a.makeSound(); } } 类 Animal 实现 BeingAnimal { public void makeSound() { } }
【解决方案2】:

如果我用一个词来说明原因,那就是:中心化。

我的意思是,您在应用程序开始时将这些具体类型分配到一个地方的某个地方,并将它们作为接口提供给需要它们的类,这样这些类就不会与具体类型耦合类型本身,而是依赖于那些抽象或接口。

这与使用Factory pattern 类似,因此您不会将对象创建分散到整个程序中,而是在一个地方进行,这样以后很容易修改。

这也使您能够使用Dependency InjectionInversion of Control,这反过来又带来了一堆好东西,比如更好的测试、可维护性、运行时配置等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-30
    • 1970-01-01
    相关资源
    最近更新 更多