2014-12-06 8 views
3

Вопрос в заголовке немного обобщен, и многие другие подобные вопросы уже были отвечены, поэтому я понимаю общую картину. В основном использование открытого поля в Java-классе создает зависимость от деталей реализации этого класса, что приводит к уменьшению количества программного обеспечения.Можно ли использовать общедоступные поля в 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 ... 
    } 
} 

мне это кажется нормально, потому что я не выставляя никаких деталей реализации, на самом деле это событие является частью интерфейса класса. Я совсем не прав на этом? Шоуд, я все еще использую геттер для взаимодействия с событием?

Другим примером, о котором я могу думать, является регистратор, который используется в классе, но может быть установлен снаружи, чтобы получить определенный уровень детализации.

Итак, чтобы расширить вопрос, можно ли использовать публичный модификатор, если поле является сторонним компонентом, к которому можно получить доступ, чтобы достичь определенного поведения?

+1

Я не активен на [programmers.SE] (http://programmers.stackexchange.com/), но это, возможно, было лучше подойдет там. – ydaetskcoR

+1

Имея «Событие», обработчики событий немного странны, и именно поэтому вы оказались с переменными 'public', которые кажутся хорошей идеей. Перечитайте [The Observer Pattern] (http://en.wikipedia.org/wiki/Observer_pattern). –

+0

@BoristheSpider, я думаю, что все дело в функциональных интерфейсах. Я думаю, что это не похоже на то, что «Событие» содержит сам обработчик, он больше похож на «Событие» содержит анонимный объект-делегат, который реализует функциональный интерфейс, я не вижу в этом ничего плохого. На самом деле мне кажется, что он очень похож на самого наблюдателя. –

ответ

-1

Существует причина, по которой вы можете объявлять поля общедоступными, но помимо простых транспортных объектов, таких как, возможно, двумерная точка, ... объявление публичного поля может привести к неожиданным результатам.

Давайте посмотрим на 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 s, ...

0

Да, в принципе нет ничего плохого в том, что у вас есть общедоступные или более неформальные поля в Java. Он поддерживается языком Java, и для них, конечно же, используются прецеденты. Сказав это, я лично использую их только в непубличных, часто вложенных вспомогательных классах. В классах, которые будут использоваться вне их пакетов, я хочу проверить значения свойств или запретить пользователю изменять экземпляры класса, я хочу обернуть коллекции в немодифицируемые представления, заменить значения по умолчанию для нулевых значений и т. Д. И когда я не хочу этого сейчас, я обычно хочу иметь возможность добавлять их позже, не разбирая много кода. Поэтому я бы сказал: нет, не-частные поля не имеют места в классах, которые принадлежат общему интерфейсу пакета.

В вашем конкретном случае для меня событие представляет собой объект, который инкапсулирует информацию об одном конкретном событии, например, одно нажатие клавиши или один щелчок мышью и т. Д. Поэтому мне неловко хранить прослушиватели событий в сам объект события, потому что это будет означать, что слушатели событий должны быть добавлены каждый раз, когда происходит событие. Для меня событие является ключевым примером класса, который, вероятно, должен быть немодифицирован. Наличие открытых полей сразу делает экземпляр класса модифицируемым, поэтому в объекте события я бы особенно советовал публичным полям.

Смежные вопросы