简体   繁体   English

Java包问题

[英]Java package woes

Ok, I'm used to structuring my projects like this 好的,我习惯于构建这样的项目

|--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)

I have one package to organize all interfaces and then the implementations are in their own related pacakges. 我有一个包来组织所有接口,然后将实现放在各自相关的文件中。

The public class FooBarService has to return instances of Foo1, Foo2, etc via their interfaces IFoo1, IFoo2, etc to callers outside this project. 公共类FooBarService必须通过其接口IFoo1,IFoo2等将Foo1,Foo2等的实例返回给此项目之外的调用方。 But class FooBarService cannot access the concrete classes Foo1, Foo2, etc as they are package scoped. 但是类FooBarService无法访问具体的类Foo1,Foo2等,因为它们是程序包范围的。

What is a good way to not expose the concrete classes to outside libraries but stil keep implementations in meaningful multiple packages? 什么是不将具体类公开给外部库,而是将实现保留在有意义的多个包中的一种好方法? or is that even possible? 甚至有可能吗? In .net I can just specify concrete classes as internal , where ever they are implemented and whatever their namespace is but I'm wondering if it's possible in java use such structure? 在.net中,我只能将具体类指定为internal ,无论它们在哪里实现以及它们的命名空间如何,但是我想知道在Java中是否可以使用这种结构?

First do you really need all those interfaces? 首先,您真的需要所有这些接口吗? Unless your building a framework, library, or you forsee multiple implementations don't go around making interfaces because it seems like good design. 除非您构建框架,库或预见多个实现,否则不要随意制作接口,因为这似乎是一个好的设计。 With modern AOP and mocking libraries and IDE's that can refactor like a charm there is very little benefit in making hundreds of interfaces. 使用现代的AOP和模拟库以及可以像魅力一样进行重构的IDE,制作数百个接口几乎没有好处。 Its especially (IMHO) stupid to make an interface for every Java Bean POJO just to hide special (or all) setters. 尤其(IMHO)愚蠢的做法是为每个Java Bean POJO都建立一个接口,以隐藏特殊(或所有)设置器。 I know it seems like good design but KISS is better. 我知道这看起来不错,但KISS更好。

Lets assume you do. 让我们假设你这样做。 You should deal with package visibility with project dependencies. 您应该使用项目依赖项来处理程序包可见性。 That is the best way is to make multiple projects eg a multi module maven project . 最好的方法是制作多个项目,例如多模块Maven项目

something like 就像是

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

The myproject build would produce three different jars (names might be different): myproject-api.jar , myproject-foo.jar , myproject-bar.jar myproject构建将产生三个不同的jar(名称可能不同): myproject-api.jarmyproject-foo.jarmyproject-bar.jar

If your looking for a more pedantic organization you should look at this guys blog but you can't really enforce it (like you can in C#) with out separating out into separate projects. 如果您要寻找一个更加古怪的组织,则应查看此人的博客,但不能真正将其实施(就像在C#中那样),而不能将其分离到单独的项目中。

You should also be familiar with the canonical Java SPI practice and dependency injection (now that its sort of standardized with @Inject ). 您还应该熟悉规范的Java SPI实践依赖项注入 (现在已经使用@Inject对其进行了标准化)。

I really don't recommend you do the @his static method factory pattern for services (especially instantiating instances of an interface). 我真的不建议您为服务(尤其是实例化接口实例)使用@his静态方法工厂模式 If you do this what happens at best is the service locator pattern but something far worse can happen where developers will wire dependent objects in the constructors (ie aggregation construction pattern) and you end up sometimes with the evil singleton pattern. 如果这样做,充其量就是服务定位器模式,但是如果开发人员将依赖对象连接到构造函数中(即聚合构造模式),并且有时最终会变成邪恶的单例模式,则可能会发生更糟的事情。 Finally static methods are always available leading to unpredictable usage and lifecycle (compared to DI). 最后,静态方法始终可用,从而导致不可预测的使用和生命周期(与DI相比)。

Also if your really adventurous you can go look at OSGI . 另外,如果您真的很喜欢冒险,可以去看看OSGI

Regardless of SPI and OSGI I highly recommend the multi-module approach. 无论SPI和OSGI如何,我都强烈建议使用多模块方法。

I am not very happy with the separation of "every interface in one package, implementations separate by type in different packages". 我对“每个接口在一个程序包中,实现按类型在不同的程序包中分离”的分离感到不满意。 I would put implementations and interfaces in one package and separate further by functionality. 我将实现和接口放在一个包中,并按功能进一步分开。 But you certainly have your good reasons. 但是,您当然有充分的理由。

Apart from the "big" solution (a module system like OSGi that hides anything except published interfaces) you can only hide concrecte classes with factories and inner classes. 除了“大型”解决方案(像OSGi这样的模块系统,它会隐藏已发布的接口以外的任何内容)之外,您只能隐藏带有工厂和内部类的具体类。 The point is to put the factories inside the impl package and to make the concrete class an inner class of the factory. 关键是将工厂放入impl包中,并使具体类成为工厂的内部类。 The factory obviously still is visible to the outside but as the point is to prevent programmers from using specifics of concrete implementations this is not a problem. 工厂显然对外部仍然可见,但是从防止程序员使用具体实现细节的角度出发,这并不是问题。

So: 所以:

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

If your intention is to prevent any deeper inspection of the classes than it indeed can't be done with pure Java; 如果您的目的是防止对类进行任何更深入的检查,这比使用纯Java确实无法做到; it is not the purpose of the visibility modifiers; 这不是可见性修改器的目的; and need some module system. 并需要一些模块系统。 But even then the class can be inspected by reflection. 但是即使这样,也可以通过反思来检查课程。

You need to have a factory class which will return you the implementation instances. 您需要有一个工厂类,它将返回您的实现实例。

Something like 就像是

if(requestedClass.equals("IFoo1"))
     return(IFoo1)new Foo1();

It is not possible to do that in Java. 用Java不可能做到这一点。 A outside librabry can create a class with the same package of your app, and it will have package visibility. 外部库可以创建与您的应用程序相同的包的类,并且具有包可见性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM