Java - 委托方法的正确方法

Gil*_*ian 6 java design-patterns software-design

我的程序从外部源获取信息(可以是文件,数据库或我将来可能决定的任何其他内容).

我想定义一个具有我所有数据需求的接口,以及实现它的类(例如,一个用于从文件获取数据的类,另一个用于DB的数据等).

我希望我的项目的其余部分不关心数据的来源,也不需要创建任何对象来获取数据,例如调用"DataSource.getSomething();"

为此,我需要DataSource包含接口类型的变量,并使用其中一个具体实现对其进行初始化,并将其所有方法(来自接口)公开为静态方法.

因此,假设接口名称为K,具体实现为A,B,C.

我今天这样做的方式是:

public class DataSource  {
    private static K myVar = new B();

    // For **every** method in K I do something like this:

    public static String getSomething() {
          return myVar.doSomething();
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

这是非常糟糕的,因为我需要复制接口的所有方法并使它们静态,因此我可以将它委托给myVar,以及许多其他明显的原因.

这样做的正确方法是什么?(也许它有一个设计模式?)

**注意 - 因为这将是许多其他项目的支柱,我将使用来自数千(如果不是数万)代码行的这些调用,我坚持像"DataSource.getSomething();"那样保持简单,我不要像"DataSource.getInstance().getSomething();"**

编辑:我在这里提供使用像Guice这样的DI框架,这是否意味着我需要在我的所有项目中的每个入口点(即"主"方法)中添加DI代码,或者有一种方法可以执行一次所有项目?

Pao*_*olo 8

使用数据源的类应该通过接口访问它,并在构造时提供给类的正确实例.

所以首先要做DataSource一个界面:

public interface DataSource {

    String getSomething();
}
Run Code Online (Sandbox Code Playgroud)

现在具体实现:

public class B implements DataSource {

    public String getSomething() {
        //read a file, call a database whatever..
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你的调用类看起来像这样:

public class MyThingThatNeedsData {

    private DataSource ds;

    public MyThingThatNeedsData(DataSource ds) {
        this.ds = ds;
    }

    public doSomethingRequiringData() {
        String something = ds.getSomething();
        //do whatever with the data
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在代码中的其他位置实例化此类:

public class Program {

    public static void main(String[] args) {
        DataSource ds = new B(); //Here we've picked the concrete implementation 
        MyThingThatNeedsData thing = new MyThingThatNeedsData(ds);  //And we pass it in
        String result = thing.doSomethingThatRequiresData();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你想获得花哨的话,你可以使用像Spring或Guice这样的依赖注入框架来完成最后一步.

加分点:在您的单元测试中,您可以提供DataSource的模拟/存根实现,而您的客户端类将更加明智!

  • 不,你不必转换为Spring.有许多好的(很多)较小的DI框架,如Guice,Dagger,HK2等.选择一个并用它进行测试.您的设计将简单而有效.这是正确的方法,即使你不认为它. (2认同)