Как круговых зависимостей можно избежать, когда обратные вызовы используются?

К сожалению, обработчик событий close не может быть настроен с помощью объекта InfoboxOptions , поэтому вы можете рассмотреть реализацию пользовательского HTML Infobox или . обработчик . В следующем примере показано, как сохранить информационное окно открытым после нажатия кнопки закрытия и добавить настраиваемое действие:

Microsoft.Maps.Events.addHandler(infobox, 'click', handleClickInfoBox);

function handleClickInfoBox(e){
  var isCloseAction = e.originalEvent.target.className == "infobox-close-img";
  if(isCloseAction){
    //keep info window open..
    e.target.setOptions({visible: true}); 
    //apply some custom actions..
    console.log("Close button clicked");
  }
}

function loadMapScenario() {
  var map = new Microsoft.Maps.Map(document.getElementById("myMap"), {
    center: new Microsoft.Maps.Location(47.60357, -122.32945)
  });
  var infobox = new Microsoft.Maps.Infobox(map.getCenter(), {
    title: "Title",
    description: "Description",
    actions: [
      {
        label: "Handler1",
        eventHandler: function() {
          console.log("Handler1");
        }
      },
      {
        label: "Handler2",
        eventHandler: function() {
          console.log("Handler2");
        }
      },
      {
        label: "Handler3",
        eventHandler: function() {
          console.log("Handler3");
        }
      }
    ]
  });
  infobox.setMap(map);
  Microsoft.Maps.Events.addHandler(infobox, 'click', handleClickInfoBox);
}

function handleClickInfoBox(e){
  var isCloseAction = e.originalEvent.target.className == "infobox-close-img";
  if(isCloseAction){
    //keep info window open..
    e.target.setOptions({visible: true}); 
    //apply some custom actions..
    console.log("Close button clicked");
  }
}
body{
   margin:0;
   padding:0;
   overflow:hidden;
}

[118 ]

9
задан Brad Cupit 28 April 2017 в 15:22
поделиться

6 ответов

Я не вижу что, будучи круговой зависимостью.

Слушатель ни от чего не зависит.

ListenerImpl зависит от Слушателя и Вещательной компании

Вещательная компания зависит от Слушателя.

        Listener
       ^        ^
      /          \
     /            \
Broadcaster <--  ListenerImpl

Все стрелки заканчиваются в Listener. Нет никакого цикла. Так, я думаю, что Вы в порядке.

9
ответ дан 4 December 2019 в 10:34
поделиться

Какой-либо язык ООП? Хорошо. Вот десятиминутная версия в CLOS.

Широковещательная платформа

(defclass broadcaster ()
  ((listeners :accessor listeners
              :initform '())))

(defgeneric add-listener (broadcaster listener)
  (:documentation "Add a listener (a function taking one argument)
  to a broadcast's list of interested parties"))

(defgeneric remove-listener (broadcaster listener)
  (:documentation "Reverse of add-listener"))

(defgeneric broadcast (broadcaster object)
  (:documentation "Broadcast an object to all registered listeners"))

(defmethod add-listener (broadcaster listener)
  (pushnew listener (listeners broadcaster)))

(defmethod remove-listener (broadcaster listener)
  (let ((listeners (listeners broadcaster)))
    (setf listeners (remove listener listeners))))

(defmethod broadcast (broadcaster object)
  (dolist (listener (listeners broadcaster))
    (funcall listener object)))

Подкласс в качестве примера

(defclass direct-broadcaster (broadcaster)
  ((latest-broadcast :accessor latest-broadcast)
   (latest-broadcast-p :initform nil))
  (:documentation "I broadcast the latest broadcasted object when a new listener is added"))

(defmethod add-listener :after ((broadcaster direct-broadcaster) listener)
  (when (slot-value broadcaster 'latest-broadcast-p)
    (funcall listener (latest-broadcast broadcaster))))

(defmethod broadcast :after ((broadcaster direct-broadcaster) object)
  (setf (slot-value broadcaster 'latest-broadcast-p) t)
  (setf (latest-broadcast broadcaster) object))

Пример кода

Lisp> (let ((broadcaster (make-instance 'broadcaster)))
        (add-listener broadcaster 
                      #'(lambda (obj) (format t "I got myself a ~A object!~%" obj)))
        (add-listener broadcaster 
                      #'(lambda (obj) (format t "I has object: ~A~%" obj)))
        (broadcast broadcaster 'cheezburger))

I has object: CHEEZBURGER
I got myself a CHEEZBURGER object!

Lisp> (defparameter *direct-broadcaster* (make-instance 'direct-broadcaster))
      (add-listener *direct-broadcaster*
                  #'(lambda (obj) (format t "I got myself a ~A object!~%" obj)))
      (broadcast *direct-broadcaster* 'kitty)

I got myself a KITTY object!

Lisp> (add-listener *direct-broadcaster*
                    #'(lambda (obj) (format t "I has object: ~A~%" obj)))

I has object: KITTY

К сожалению, Lisp решает большинство проблем шаблона разработки (такой как Ваш) путем избавления от необходимости их.

7
ответ дан 4 December 2019 в 10:34
поделиться

В отличие от ответа Херма, я действительно вижу цикл. Это не цикл зависимостей, это - ссылочный цикл: LI содержит объект B, объект B содержит (Массив) объект (объекты) LI. Они не освобождают легко и заботятся о потребностях, которые будут взяты, чтобы гарантировать, чтобы они освободили, если это возможно.

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

4
ответ дан 4 December 2019 в 10:34
поделиться

Я не Java dev, но что-то вроде этого:

public class ListenerImpl implements Listener {
  public Foo() {}
  public void registerWithBroadcaster(Broadcaster b){ b.register(this); isRegistered = true;}
  public void callBack(Object arg) { if (!isRegistered) throw ... else ... }
  public void shutDown() { isRegistered = false; }
}

public class Broadcaster {
  private final List listeners = new ArrayList();
  public void register(Listener lis) { listeners.add(lis); }
  public void unregister(Listener lis) {listeners.remove(lis); }
  public void broadcast(Object arg) { for (Listener lis : listeners) { if (lis.isRegistered) lis.callBack(arg) else unregister(lis); } }
}
0
ответ дан 4 December 2019 в 10:34
поделиться

Используйте слабые ссылки для повреждения цикла.

См. этот ответ.

0
ответ дан 4 December 2019 в 10:34
поделиться

Вот пример в Lua (я использую свой собственный lib ООП здесь, вижу ссылки для 'Возражения' в коде).

Как в примере Mikael Jansson CLOS, Ваш может использовать функции непосредственно, устраняя необходимость определения слушателей (отметьте использование '...', это - varargs Lua):

Broadcaster = Object:subclass()

function Broadcaster:initialize()
    self._listeners = {}
end

function Broadcaster:register(listener)
    self._listeners[listener] = true
end

function Broadcaster:unregister(listener)
    self._listeners[listener] = nil
end
function Broadcaster:broadcast(...)
    for listener in pairs(self._listeners) do
        listener(...)
    end
end

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

--# Listener
Listener = Object:subclass()
function Listener:callback(arg)
    self:subclassResponsibility()
end

--# ListenerImpl
function ListenerImpl:initialize(broadcaster)
    self._broadcaster = broadcaster
    broadcaster:register(this)
end
function ListenerImpl:callback(arg)
    --# ...
end
function ListenerImpl:shutdown()
    self._broadcaster:unregister(self)
end

--# Broadcaster
function Broadcaster:initialize()
    self._listeners = {}
end
function Broadcaster:register(listener)
    self._listeners[listener] = true
end
function Broadcaster:unregister(listener)
    self._listeners[listener] = nil
end
function Broadcaster:broadcast(arg)
    for listener in pairs(self._listeners) do
        listener:callback(arg)
    end
end
0
ответ дан 4 December 2019 в 10:34
поделиться
Другие вопросы по тегам:

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