【问题标题】:Java interfaces, the creator patterns and the "getInstance()" method or equivalentJava 接口、创建者模式和“getInstance()”方法或等效方法
【发布时间】:2011-10-12 07:28:16
【问题描述】:

我想首先提到我的问题源于 Java 中的接口不允许静态方法这一事实。在 SO(例如,here)上已经讨论了这个原因。因此,让我们不要纠缠于此。我正在为我的接口寻找一种方法来创建它自己的实例(而不是它的实现)并返回它。尽管使用了 Singleton 模式、Factory 和 AbstractFactory 模式,我仍然无法实现我的目标。

详细说明我正在尝试的内容 - 这是我的界面:

public interface NoteDataStore {
    public boolean deleteNote(long noteId);
    public boolean addNote(Note note);
    public List<Note> listNotes();
    public boolean editNote(long noteId, Note note);
    public List<Note> search(String searchString);
}

这是我的业务逻辑层:

public class BusinessLogicLayer {

    public BusinessLogicLayer(){
        /*
         * GOAL: To get an instance of NoteDataStore here,
         *  without being aware of the implementation class.
         */
    }

}

我尝试使用这样的工厂模式:

public interface NoteDataStoreFactory {
    public NoteDataStore getDataStoreInstance();
}

public class NoteDataStoreFactoryImpl implements NoteDataStoreFactory{
    public NoteDataStore getDataStoreInstance(){
        return NoteDataStoreImpl.getInstance();
        /*
         * Here, NoteDataStoreImpl is an implementation of NoteDataStore.
         * This should be transparent to my business logic layer.
         */
    }
}

但是,这仍然需要业务逻辑层知道实现类NoteDataStoreFactoryImpl,因此:

NoteDataStore = new NoteDataStoreFactoryImpl().getDataStoreInstance();

我该如何解决这个问题?如何让我的 BusinessLogicLayer 不知道要使用的具体实现类?


编辑:我的问题的更详细背景

一些答案​​建议使用 Spring 等框架。唉,我不能这样做,因为这个应用程序针对各种移动平台(Android、Blackberry、JavaME)。我应该在最初的问题中说明这一点 - 很抱歉没有这样做。

我的主要目的是开发一个跨平台的应用程序。 UI、数据库访问、HTTP 传输层等必须专门针对每个平台进行编码。但是,业务逻辑足够简单,可以保证跨所有平台的通用层。我打算将业务逻辑层分发为 JAR 库。解析和框架层(用于 JSON/XML)也是如此。

SO 已经讨论过这个问题(关于我是否应该走这条路)-Logic Code reuse。但是,假设这没问题,并且我继续使用分层方法并打算在代码中使用一个通用层。现在,我的情况是这样的:

  1. 通用业务逻辑层。
  2. 特定于平台的数据层(由NoteDataStore 接口表示)
  3. 特定于平台的应用程序核心层(控制器,如果我可以这样称呼的话)。

请注意,如果我使用工厂模式或其他类似模式,我可以负担得起特定于每个平台的该层。因此,工厂方法/类本身可以知道NoteDataStore 实现类。但是,业务逻辑层必须不知道任何实现类。

各种层的典型用法如下:

public class NoteDataStoreAndroid implements NoteDataStore{

    public boolean deleteNote(long noteId){
        /*
         * Android-specific database code
         */
    }

    /* ... similarly, other methods */
}


public class AndroidCoreApp{

    public void doBusinessLogic(){
        BusinessLogicLayer businessLogic = new BusinessLogicLayer();
        businessLogic.startBusinessLogic();
    }
}

关于如何处理这种情况的任何意见?

【问题讨论】:

  • 为什么不将 NoteDataStoreFactory 的实例传递给 BusinessLogicLayer 构造函数?
  • 事实上@Ray Tayek,我什至不需要工厂类。我可以直接将NoteDataStore 的实例传递给BusinessLogicLayer 构造函数——这是有道理的,因为“控制器”层是创建NoteDataStore 的具体实例的最佳位置。

标签: java design-patterns abstract-factory


【解决方案1】:

你的类应该接受来自外部的工厂实例。当您自己创建实例时 - 您一无所获,您在这里是正确的。

这里有几种技术。一般来说,它们属于非常笼统的东西,称为Inversion of Control 或简称为 IoC。了解“控制容器的反转”或 IoCC 也很有用。 Java 有 Spring 例如 - 阅读here。你应该向真正的 Java 人询问其他人的情况:)

也看看这个article

【讨论】:

  • 感谢您的详细回复。不幸的是,我没有使用 Spring 或其他框架的奢侈。请参阅编辑后的问题,了解我为什么这么说的详细信息。我想我可能必须自己实现 IoC 技术。
  • @techie:嗯,使用 IoC 并不一定意味着它应该像 Spring 一样可怕。例如,服务定位器可能非常便宜且易于编写。老实说,我很确定在 Java 领域存在着某种小型的 IoCC 类型,专门针对移动设备。我自己不是一个javist,所以在这里不能给你很好的建议。尝试提出有关 Java 中不同轻量级 IoCC 的新问题。
【解决方案2】:

如果你想返回一个实现,你可以使用匿名内部类

NoteDataStore myImplementation = new NoteDataStore (){
//Implement methods here
};

【讨论】:

  • @OscarMk,感谢您的建议。我认为它在某些情况下会很好用。不过,我还在想它如何适合我的。有关我的确切情况的更多详细信息,请参阅编辑后的问题。
【解决方案3】:

您是否查看过 Guice 和 Spring 等 IoC/依赖注入框架?对于您正在寻找的东西,它们可能太重了,但它们绝对可以解决您描述的问题。它们允许针对接口编写所有业务层代码,并通过 IoC 框架定义实际实现。我个人是 Spring 的忠实拥护者,并且在过去 6 年多的时间里,几乎在我编写的所有 Java 应用程序中都使用了它。

【讨论】:

  • 我无法使用框架。有关我的方案的更多详细信息,请参阅问题(已编辑)。再次,很抱歉一开始没有提及这些细节!
【解决方案4】:

我终于接受了@Ray Tayek 在对原始问题的评论中提供的建议。我只是在创建BusinessLogicLayer 时传入NoteDataStore 的一个实例。

这个简单的解决方案非常适合我的需求,因为我并不真正需要工厂。我的主要目标是让 BL 层不知道它使用的接口的确切实现类。现在,它不是工厂,而是核心“控制器”层,它创建接口的具体实现并将它们提供给 BL 层。这简直太完美了!

这里是代码sn-p。

public class NoteDataStoreAndroid implements NoteDataStore{

    public boolean deleteNote(long noteId){
        /*
         * Android-specific database code
         */
    }

    /* ... similarly, other methods */
}


public class AndroidCoreApp{

    public void doBusinessLogic(){
        BusinessLogicLayer businessLogic = new BusinessLogicLayer(new NoteDataStoreAndroid());
        businessLogic.startBusinessLogic();
    }
}

public class BusinessLogicLayer {

    private NoteDataStore mDataStore;
    public BusinessLogicLayer(NoteDataStore dataStore){
        this.mDataStore = dataStore;

        //Do something useful with mDataStore
    }

    public void startBusinessLogic(){
        //Do something useful with mDataStore
    }

}

【讨论】:

    【解决方案5】:

    建议您使用 ID 框架,如 Guice 等。不要简单地使用工厂模式。

    【讨论】:

    • 虽然这可能是解决问题的宝贵提示,但一个好的答案也可以证明解决方案。请EDIT 提供示例代码来说明您的意思。或者,考虑将其写为评论
    猜你喜欢
    • 1970-01-01
    • 2021-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-22
    • 1970-01-01
    • 2015-11-06
    • 1970-01-01
    相关资源
    最近更新 更多