Как объявить и использовать события в Java

если мы предполагаем, что точка x больше, чем точка y, если угол, который это имеет с точкой (0,0), больше тогда, мы можем реализовать этот этот путь в c#

    class Point : IComparable<Point>
    {
        public int X { set; get; }
        public int Y { set; get; }

        public double Angle
        {
            get
            {
                return Math.Atan2(X, Y);
            }
        }

        #region IComparable<Point> Members

        public int CompareTo(Point other)
        {
            return this.Angle.CompareTo(other.Angle);
        }

        #endregion

        public static List<Point>  Sort(List<Point> points)
        {
            return points.Sort();
        }
}
10
задан AngryHacker 12 October 2009 в 06:26
поделиться

7 ответов

Если вы хотите избежать наследования от базового класса, подобного java.util.Observable, используйте интерфейс и позвольте вашим наблюдаемым объектам реализовывать или делегировать методы интерфейса.

Вот наблюдаемый интерфейс :

public interface IObservable
{
        void addObserver(IObserver o);

        void deleteObserver(IObserver o);

        void notifyObservers(INotification notification);
}

Вот вспомогательный класс, который может использоваться вашими реальными наблюдаемыми:

import java.util.ArrayList;
import java.util.List;


public class Observable implements IObservable
{
        private List<IObserver> observers;

        @Override
        public synchronized void addObserver(IObserver o)
        {
                if (observers == null)
                {
                        observers = new ArrayList<IObserver>();
                }
                else if (observers.contains(o))
                {
                        return;
                }
                observers.add(o);
        }

        @Override
        public synchronized void deleteObserver(IObserver o)
        {
                if (observers == null)
                {
                        return;
                }
                int idx = observers.indexOf(o);
                if (idx != -1)
                {
                        observers.remove(idx);
                }
        }

        @Override
        public synchronized void notifyObservers(INotification notification)
        {
                if (observers == null)
                {
                        return;
                }
                for (IObserver o : observers)
                {
                        o.update(notification);
                }
        }

}

Настоящая наблюдаемая может выглядеть так:

class Person implements IObservable
{
        private final IObservable observable = new Observable();

        @Override
        public void setFirstName(String firstName) throws Exception
        {
            if (firstName == null || firstName.isEmpty())
            {
                    throw new Exception("First name not set");
            }

            this.firstName = firstName;
            notifyObservers(new Notification(this, getFirstNamePropertyId()));
        }

    @Override
    public void addObserver(IObserver o)
    {
            observable.addObserver(o);
    }

    @Override
    public void deleteObserver(IObserver o)
    {
            observable.deleteObserver(o);
    }

    @Override
    public void notifyObservers(INotification notification)
    {
            observable.notifyObservers(notification);
    }

    private static final String FIRSTNAME_PROPERTY_ID = "Person.FirstName";

    @Override
    public String getFirstNamePropertyId()
    {
            return FIRSTNAME_PROPERTY_ID;
    }

}

Вот интерфейс наблюдателя:

public interface IObserver
{
        void update(INotification notification);
}

Наконец, вот интерфейс уведомлений и базовая реализация:

public interface INotification
{
        Object getObject();

        Object getPropertyId();
}

public class Notification implements INotification
{
        private final Object object;
        private final Object propertyId;

        public Notification(Object object, Object propertyId)
        {
                this.object = object;
                this.propertyId = propertyId;
        }

        @Override
        public Object getObject()
        {
                return object;
        }

        @Override
        public Object getPropertyId()
        {
                return propertyId;
        }
}
9
ответ дан 3 December 2019 в 13:37
поделиться

Предполагая, что переданное целое число является частью состояния класса Animal, идиоматический способ сделать это вместо написания большого количества собственного кода - запустить ] PropertyChangeEvent . Для этого можно использовать класс PropertyChangeSupport , сократив код до следующего:

public class Animal {
  // Create PropertyChangeSupport to manage listeners and fire events.
  private final PropertyChangeSupport support = new PropertyChangeSupport(this);
  private int foo;

  // Provide delegating methods to add / remove listeners to / from the support class.  
  public void addPropertyChangeListener(PropertyChangeListener l) {
    support.addPropertyChangeListener(l);
  }

  public void removePropertyChangeListener(PropertyChangeListener l) {
    support.removePropertyChangeListener(l);
  }

  // Simple example of how to fire an event when the value of 'foo' is changed.
  protected void setFoo(int foo) {
    if (this.foo != foo) {
      // Remember previous value, assign new value and then fire event.
      int oldFoo = this.foo;
      this.foo = foo;
      support.firePropertyChange("foo", oldFoo, this.foo);
    }
  }
}

Наконец, я бы не советовал использовать Observer / Observable так как это делает код нечитаемым / трудным для понимания: вам постоянно приходится проверять тип аргумента, переданного Observer , используя instanceof перед его понижением, и трудно увидеть, какой тип события ожидает конкретная реализация Observer, глядя на определение его интерфейса.

21
ответ дан 3 December 2019 в 13:37
поделиться

Простой интерфейс событий выглядит следующим образом:

public interface AnimalListener {
    public void animalDoesSomething(int action);
}

Animal должен управлять своими слушателями:

public class Animal {
    private final List<AnimalListener> animalListeners = new ArrayList<AnimalListener>()
    public void addAnimalListener(AnimalListener animalListener) {
        animalListeners.add(animalListener);
    }
}

Ваш класс, создающий Animal , должен делать следующее:

public class AnimalCreator implements AnimalListener {
    public void createAnimal() {
        Animal animal = new Animal();
        animal.addAnimalListener(this); // implement addListener in An
    }
    public void animalDoesSomething(int action) {
        System.ot.println("Holy crap, animal did something!");
    }
}

Теперь Animal может запускать события.

public class Animal {
    ....
    public void doSomething() {
        for (AnimalListener animalListener : animalListeners) {
            animalListener.animalDoesSomething(4);
        }
    }
}

Это похоже на большой объем кода для чего-то столь же простого, как «запуск событий», но, возможно, запуск событий совсем не прост. :)

Конечно, у этого простого механизма есть различные расширения.

  • Я всегда расширяю свои прослушиватели событий java.util.EventListener .
  • Первым параметром для каждого метода прослушивателя должен быть источник события, то есть public void animalDoesSomething (Animal animal, int action); .
  • Управление зарегистрированными слушателями и запуском событий можно абстрагировать до некоторого вида абстрактного класса управления слушателями событий. Посмотрите на PropertyChangeSupport , чтобы понять, что я имею в виду.
5
ответ дан 3 December 2019 в 13:37
поделиться

См. java.util.Observable

РЕДАКТИРОВАТЬ: подход Адамски PropertyChangeSupport , основанный на подходе Адамски, кажется лучше Наблюдаемый, который я предложил.

3
ответ дан 3 December 2019 в 13:37
поделиться

Классы Observer / Observable присутствуют в Java с первого дня. К сожалению, первоначальные дизайнеры несколько облажались. Честно говоря, у них не было возможности поучиться на 10-летнем опыте работы с Java ...

Я решаю вашу проблему с делегированием. У меня есть собственная реализация Observer / Observable - и я рекомендую это. Но вот подход, который работает:

import java.util.Observable;
import java.util.Observer;

public class Animal {

    private final ImprovedObservable observable = new ImprovedObservable();

    public void addObserver(Observer o) {
        observable.addObserver(o);
    }

    public void notifyObservers() {
        observable.notifyObservers();
    }

    public void doSomething() {
        observable.setChanged();
        observable.notifyObservers(new AnimalEvent());
    }


}

// simply make setChanged public, and therefore usable in delegation
class ImprovedObservable extends Observable {
    @Override
    public void setChanged() {
        super.setChanged();
    }
}

class AnimalEvent {
}
2
ответ дан 3 December 2019 в 13:37
поделиться

Мое первое предложение - взглянуть на AspectJ. Это один из шаблонов проектирования, с которым язык лучше всего справляется. В следующей статье очень красноречиво описывается, как это можно реализовать:

http://www.ibm.com/developerworks/java/library/j-aopwork6/index.html

1
ответ дан 3 December 2019 в 13:37
поделиться

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

0
ответ дан 3 December 2019 в 13:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: