在Java中使用公共字段是否可以?

时间:2014-12-06 11:09:54

标签: java public

标题中的问题有点通用,许多其他类似问题已经得到解答,所以我理解了总体情况。主要是,在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 ...
    }
}

对我来说,这似乎很好,因为我没有公开任何实现细节,实际上事件是类的接口的一部分。 我对此完全错了吗?我仍然使用吸气剂来与事件互动?

我能想到的另一个例子是在类中使用的记录器,但可以从外部设置以获得一定程度的细节。

因此,要扩展问题,如果字段是可以访问以实现特定行为的第三方组件,是否可以使用公共修饰符?

2 个答案:

答案 0 :(得分:0)

您可以将字段声明为public,但除了简单的传输对象(如可能是二维点)之外,...声明字段公开可能会导致意外结果。

让我们看看SomeClass并将其扩展为SomeChildClassSomeGrandChildClass,如下所示:

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语言的支持,当然也有用例。话虽如此,我个人倾向于只在非公开的,通常是嵌套的辅助类中使用它们。在将要在其包之外使用的类中,我想验证属性的值或禁止用户修改类的实例,我想将集合包装在不可修改的视图中,将默认值替换为空值等。而当我现在不想要它时,我通常希望以后能够添加它们而不会破坏很多代码。所以我想说:不,非私有字段在属于包的公共接口的类中没有位置。

在您的特定情况下,对我来说,事件是一个对象,它封装了一个特定事件的信息,例如单键按下或单击鼠标等。所以我觉得将事件监听器存储在事件对象本身,因为这意味着每次事件发生时都必须添加事件侦听器。对我来说,事件是类的一个关键例子,它应该是不可修改的。公共字段立即使类的实例可修改,因此在事件对象中我特别建议对公共字段。