Java类范围和库
我正在创建一个Java库,作为最终产品,打算将这个.jar分发给开发人员。
我正在从Objective-C“翻译”我的库,在那里我控制哪些类头文件可供开发人员使用。 换句话说,我只向开发人员展示他们可以处理的几个类。
在我的Java库中,我正在使用包,而且我的包已经变得非常大。 所以我决定将我的模型和控制器分成不同的包。 但是现在我希望保密的模型我需要标记为公共,以便从主包中使用。
我的问题是,这与我在Objective-C中做的事情有什么不同吗?
例如,我有一个Event类,它实际上只在内部使用,我不希望用户知道它或考虑它。 我有另一个类TimedEvent,用户可以获取一个管理实例。
在我的Objective-C中,我只是从库公共范围中排除了Event类,允许使用TimedEvent。
如果我在我的库中使事情变得更整洁,那么包装似乎不是那样的。 从现在开始,我的主控制器在主包中,所有模型都在另一个包中 – 被迫拥有一个公共范围。
意见?
这是可能的Java,但有理由(几乎)没有人这样做…
如果将实现和接口放在同一个包中,那么可以省略类和方法中的所有访问修饰符( private
, protected
, public
),以赋予它们“默认”或“包”可见性:只有同一个包中的类才是允许查看/使用它们。
缺点:您必须混合使用API和实现。
另一种方法是将实现移动到包*.private.*
。 不再混合API和实现,但恶意用户可以轻松访问实现 – 它只是一个命名约定。 就像一个停止标志:它意味着什么(“小心”),但实际上并没有阻止你。
最后,您可以在界面内部实现接口。 例如:
public interface IFoo { String getName(); private static class Foo implements IFoo { public String getName(); } public static class FooFactory { public static IFoo create() { return new Foo(); } } }
丑,不是吗?
控制类暴露于世界的常用方法是隐藏接口和工厂背后的实现。
- 为
TimedEvent
创建一个接口,并创建一个用于创建TimedEvent
接口实例的TimedEvent
- 将接口放在主包中,将工厂放在子包中
- 让工厂公众可见
- 在子包中实现接口,为其提供包可见性
- 在工厂中创建实现
TimedEvent
接口的类的实例
以下是如何执行此操作的示例:
package com.my.main; public interface TimedEvent { void fire(); } package com.my.main.events; import com.my.main; public class EventFactory { public TimedEvent makeTimedEvent() { return new TimedEvent (); } } // TimedEventImpl has package visibility - it is not public. class TimedEventImpl implements TimedEvent { public void fire() { // Fire a timed event } }
用户可以像这样访问TimedEvent
:
com.my.main.events.EventFactory f = new com.my.main.events.EventFactory(); com.my.main.TimedEvent evt = f.makeTimedEvent(); evt.fire();