1

好的,我习惯于像这样构建我的项目

|--com.mycompany.interfaces
|         |--IFoo1(public)
|         |--IFoo2(public)
|         |--IBar1(public)
|         |--IBar2(public)
|
|--com.mycompany.foos.impl
|         |--Foo1(default) implements IFoo1
|         |--Foo2(default) implements IFoo2
|
|--com.mycompany.bars.impl
|         |--Bar1(default) implements IBar1
|         |--Bar2(default) implements IBar2
|
|--com.mycompany.services
|         |-FooBarService (public)

我有一个包来组织所有接口,然后实现在它们自己的相关包中。

公共类 FooBarService 必须通过接口 IFoo1、IFoo2 等将 Foo1、Foo2 等的实例返回给该项目外的调用者。但是类 FooBarService 不能访问具体类 Foo1、Foo2 等,因为它们是包作用域的。

什么是不将具体类公开给外部库但仍将实现保留在有意义的多个包中的好方法?或者这甚至可能吗?在.net中,我可以将具体类指定为internal,它们在哪里实现以及它们的命名空间是什么,但我想知道在java中是否可以使用这种结构?

4

4 回答 4

2

首先,您真的需要所有这些接口吗?除非您构建一个框架、库,或者您预见到多个实现,否则不要四处制作接口,因为它看起来像是好的设计。使用现代 AOP 和模拟库以及可以像魅力一样重构的 IDE,制作数百个接口几乎没有什么好处。为每个 Java Bean POJO 创建一个接口只是为了隐藏特殊的(或所有)setter 是特别愚蠢的(恕我直言)。我知道这似乎是不错的设计,但 KISS 更好。

让我们假设你这样做。 您应该处理具有项目依赖关系的包可见性。最好的方法是制作多个项目,例如多模块 maven 项目

就像是

myproject
|  | myproject-api  // interfaces here, depends on pretty much nothing
|  |  | src
|  |  | pom.xml // or build.xml or whatever
|  | myproject-foo // implementations here, depends on myproject-api
|  |  | src
|  |  | pom.xml // or build.xml or whatever
|  | myproject-bar //implementations here, depends on myproject-api and maybe foo.
|  |  | src
|  |  | pom.xml // or build.xml or whatever
|  pom.xml  // or build.xml or whatever

myproject 构建将生成三个不同的 jar(名称可能不同):myproject-api.jar, myproject-foo.jar,myproject-bar.jar

如果你正在寻找一个更迂腐的组织,你应该看看这个家伙的博客,但你不能真正执行它(就像你在 C# 中一样)而不分离成单独的项目。

您还应该熟悉规范的 Java SPI 实践依赖注入(现在它已经标准化了@Inject)。

我真的不建议您为服务(尤其是实例化接口的实例)执行@his 静态方法工厂模式。如果你这样做,充其量会发生服务定位器模式,但更糟糕的情况可能会发生,开发人员将在构造函数中连接依赖对象(即聚合构造模式),有时你会遇到邪恶的单例模式。最后,静态方法始终可用,导致不可预测的使用和生命周期(与 DI 相比)。

此外,如果您真的很喜欢冒险,您可以去看看 OSGI

无论 SPI 和 OSGI 如何,我都强烈推荐多模块方法。

于 2013-04-03T02:40:11.407 回答
1

我对“一个包中的每个接口,不同包中按类型分开的实现”的分离不太满意。我会将实现和接口放在一个包中,并按功能进一步分开。但你当然有充分的理由。

除了“大”解决方案(像 OSGi 这样的模块系统,除了已发布的接口之外隐藏任何东西),您只能隐藏带有工厂和内部类的具体类。关键是将工厂放在impl包内,并使具体类成为工厂的内部类。工厂显然仍然对外可见,但关键是防止程序员使用具体实现的细节,这不是问题。

所以:

package com.mycompany.foos.impl
public class FooFactory {
    private static class FooImpl implements IFoo1 {
        ...
    }
    public static IFoo getFoo() {
        return new FooImpl();
    }
}

如果您的意图是防止对类进行任何更深入的检查,那么纯 Java 确实无法做到;这不是可见性修饰符的目的;并且需要一些模块系统。但即便如此,也可以通过反射检查该类。

于 2013-04-03T02:56:26.730 回答
0

您需要有一个工厂类,它将返回您的实现实例。

就像是

if(requestedClass.equals("IFoo1"))
     return(IFoo1)new Foo1();
于 2013-04-03T02:32:54.560 回答
-1

在 Java 中不可能做到这一点。外部库可以使用与您的应用程序相同的包创建一个类,并且它将具有包可见性。

于 2013-04-03T02:35:10.383 回答