将接口与其实现分离的重点是什么?

时间:2017-03-05 13:26:42

标签: java design-patterns

这是企业Java级别的常见设计(但是,大多数时间引用都是由某些框架/库注入的):

我有一个界面

import java.util.*;
public interface ProductRepository {
    public List <Product> getAllProducts();
}

及其实施

public class ProductRepositoryImp implements ProductRepository {
    private List<Product> products = new ArrayList<Product>();
    public ProductRepositoryImp() {
        products.add(new Product("Blackberry", 24000));
        products.add(new Product("Nokia", 45000));
        products.add(new Product("Samsung", 91000));
    }
    @Override
    public List<Product> getAllProducts() {
        return this.products;
    }
    public int localMethod(){
        return 2;
    }

}

在主类(控制器)中,我引用了接口(ProductRepository)而不是实现(ProductRepositoryImp

public class ProductController {
    static ProductRepository productRepository;
    public static void main(String[] args) {
        productRepository = new ProductRepositoryImp();

        for (Product p : productRepository.getAllProducts()) {
            System.out.println(p.getName());
            System.out.println(p.getPrice());
            System.out.println("");
        } } }

为什么?

以下是我在一本书中读到的解释:

  

连接两个不是最好的做法           层(控制器和持久性)与直接引用。相反,我们将来可以拥有一个           控制器中的接口引用,以便我们可以轻松切换到不同的实现           没有在控制器类中进行任何代码更改的存储库。

.getAllProducts()实例而不是ProductRepository的实例访问ProductRepositoryImp有什么好处?

上面引用的“没有进行任何代码更改”切换的重点是什么?我知道如果我们有相关的东西 我们说“AnotherProductRepositoryImp”?

如果我想大量访问.localMethod()实例中的某些 ProductRepositoryImp 会怎样?

2 个答案:

答案 0 :(得分:2)

  

从中访问.getAllProducts()的好处是什么?   ProductRepository实例而不是实例   ProductRepositoryImp?

ProductRepository是您数据层的接口。它与底层数据库完全无关。

  

在没有做任何代码更改的情况下切换的重点是什么   引用上面?我知道如果我们有话要说,这是相关的   “AnotherProductRepositoryImp”?

在这种情况下,它与AnotherProductRepositoryImp无关,但可以说底层数据库发生了变化。每个数据库都有不同的查询格式,查询的相应实现在ProductRepositoryImpl类中。更改不会是AnotherProductRepositoryImp,而是ProductMongoRepositoryImpProductMySqlRepositoryImpProductFileRepositoryImp

如果要对接口进行编码,则无需对控制器进行任何更改。只需注入另一个实现就可以了。

  

如果我想重新访问某些.localMethod()而不是它   在ProductRepositoryImp实例中?

如果您使用的任何方法不是接口的一部分并且仅在您的实现内部使用,那么它不是与接口签订合同的一部分,也不需要暴露给外部世界(即声明它是私有的) )。 如果要暴露给外界,则意味着它超出了与界面的合同。您通常需要对正确的实例类型进行类型转换以访问该值。

答案 1 :(得分:2)

好处是您可以在控制器中注入另一个实现,例如用于测试的模拟存储库或用于其他SQL方言的存储库。

将接口与实现分开也可用于明确调用者打算使用哪些方法(参见information hiding,封装),尽管这也可以通过访问修饰符(例如{{ 1}})。重要的是团队同意他们使用哪种信号机制来避免误解。

虽然许多早期企业框架强制使用接口,但最明显的是EJB直到版本3.1,现代框架不再强制执行。

今天,是否应该存在只有一个实现的接口,这有点争论。有些人说是肯定是为了保持一致,有些人说不是为了简单。