标题中的问题有点通用,许多其他类似问题已经得到解答,所以我理解了总体情况。主要是,在Java类中使用公共字段会产生依赖于类的实现细节,这会导致较少的可维护软件。
考虑到这一点,我仍然觉得我可以以某种方式使用它们。为了解释这一点,我将使用一个例子:随着即将推出的Java 8的功能接口,我终于可以使用我喜欢的事件模型,这类似于在C#中处理事件的方式。
事件模型在一个包中实现,该包用于在我的所有项目中用作第三方API。 这些是主要的课程:
EventArgs.java
public class EventArgs implements Serializable {
}
EventHandler.java
@FunctionalInterface
public interface EventHandler<T extends EventArgs> {
void fire(Object sender, T args);
}
Event.java
public class Event<T extends EventArgs> {
private final Set<EventHandler<T>> handlers = new LinkedHashSet<>();
public void addEventHandler(EventHandler<T> handler) {
handlers.add(handler);
}
public void removeEventHandler(EventHandler<T> handler) {
handlers.remove(handler);
}
public void fire(Object sender, T args) {
for (EventHandler<T> e : handlers) {
e.fire(sender, args);
}
}
}
我喜欢在我的课堂上做的事情就是这样:
public class SomeClass {
public final Event<SomeEventArgs> someEvent = new Event<>();
public void someMethod() {
// ...
someEvent.fire();
}
}
并且在想要订阅事件的类中:
public class SomeOtherClass {
private SomeClass someInstance;
public SomeOtherClass() {
someInstance = new SomeClass();
someInstance.someEvent.addEventHandler(this::someEventHandler);
}
private void someEventHandler(Object sender, SomeEventArgs args) {
// do some stuff ...
}
}
对我来说,这似乎很好,因为我没有公开任何实现细节,实际上事件是类的接口的一部分。 我对此完全错了吗?我仍然使用吸气剂来与事件互动?
我能想到的另一个例子是在类中使用的记录器,但可以从外部设置以获得一定程度的细节。
因此,要扩展问题,如果字段是可以访问以实现特定行为的第三方组件,是否可以使用公共修饰符?
答案 0 :(得分:0)
您可以将字段声明为public,但除了简单的传输对象(如可能是二维点)之外,...声明字段公开可能会导致意外结果。
让我们看看SomeClass
并将其扩展为SomeChildClass
和SomeGrandChildClass
,如下所示:
public class SomeChildClass extends SomeClass {
public SomeChildClass() {
super();
someEvent.addEventHandler(...);
}
}
和
public class SomeGrandChildClass extends SomeChildClass {
public SomeGrandChildClass() {
super();
// Lets say FilteredEvent will ensure a Event will only be fired if a condition holds
someEvent = new FilteredEvent();
}
}
那发生了什么?由于超级构造函数和构造函数之间的调用顺序,我们只丢失了EventHandler
。我可以想到从外部通过特定实现替换某个Event
似乎是个好主意的不同情况(因为该字段是公共的)。您当然可以使用public final
来阻止重新分配,但是您再次失去了覆盖子类行为的机会。
所以Event
- 类很酷,但是实现addSomeHandler
- 和removeSomeHandler
- 方法可以确保子类可以使用不同的事件管理并包含父级侦听器,如果他们也使用覆盖功能。
其他示例可以是Event
- 处理机制的更改。如果您实现这些简短的方法,您可以立即包装旧式处理程序,将它们分配给其他Event
,...
答案 1 :(得分:0)
是的,原则上在Java中使用公共或非私有字段没有任何问题。它受Java语言的支持,当然也有用例。话虽如此,我个人倾向于只在非公开的,通常是嵌套的辅助类中使用它们。在将要在其包之外使用的类中,我想验证属性的值或禁止用户修改类的实例,我想将集合包装在不可修改的视图中,将默认值替换为空值等。而当我现在不想要它时,我通常希望以后能够添加它们而不会破坏很多代码。所以我想说:不,非私有字段在属于包的公共接口的类中没有位置。
在您的特定情况下,对我来说,事件是一个对象,它封装了一个特定事件的信息,例如单键按下或单击鼠标等。所以我觉得将事件监听器存储在事件对象本身,因为这意味着每次事件发生时都必须添加事件侦听器。对我来说,事件是类的一个关键例子,它应该是不可修改的。公共字段立即使类的实例可修改,因此在事件对象中我特别建议对公共字段。