Как реализовать шаблон MVC, не поддерживая представления - PullRequest
5 голосов
/ 22 июля 2010

Я бы хотел реализовать шаблон MVC в сложной ситуации. Сложность заключается в том, что мои Модели (сущности, генерирующие события) являются долгоживущими, а представления (получатели событий) - недолговечными. Моя проблема заключается в том, что благодаря связи между ними долгоживущие Модели поддерживают мои недолговечные представления, то есть они не могут быть собраны мусором.

  [MODEL] ------- <weak> -------> [VIEW]
     |
 <strong>
     |
     v
[CONTROLLER]

Способ обойти это - сохранить соединения в модели в WeakHashMap . Это по существу позволяет собирать мусор в представлении, и когда это происходит, WeakHashMap также выбрасывает соответствующий контроллер. То есть, если Контроллер не содержит (сильную) ссылку на Представление - что он обычно делает. В этом случае представления сохраняются через сильные ссылки до тех пор, пока модель не выйдет из области видимости.

  [MODEL] ------- <weak> -------> [VIEW]
     |                               ^
 <strong>                            |
     |                               |
     v                               |
[CONTROLLER] ----------- <strong> ---/

Есть ли другой способ присоединить слушателей к моим моделям, которые не поддержат мои представления (и контроллеры)?

ОБНОВЛЕНИЕ: Чтобы ответить на вопрос mdma: контроллер сохраняет ссылку на представление, поскольку ему необходимо обновить представление. Эта ссылка может быть слабой, но я хотел бы, чтобы Controllers были анонимными внутренними классами класса View, и в этом случае экземпляр Controller имеет неявную строгую ссылку на экземпляр View.

Ответы [ 4 ]

3 голосов
/ 22 июля 2010

Есть несколько способов сделать MVC.

  • Напишите модель, затем позвольте вашему представлению выслушать изменения в модели. Представление сообщает контроллеру, когда что-то происходит.
  • Напишите представление, а затем позвольте вашей модели прослушивать изменения в представлении. Представление сообщает контроллеру, когда что-то происходит.
  • Написать вид. Позвольте вашей модели слушать изменения в представлении. Пусть ваш контроллер прослушивает представление, которое будет вызывать различные события, если что-то случится.

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

Мне нравится MVCP:

  • Позвольте вашему контроллеру обернуть модель в презентере. Контроллер прислушивается к присоединяемым представлениям и каждый раз передает им нового докладчика. Ведущий делегирует изменения полей в Модель, а также делегирует команды контроллеру. Ни Контроллер, ни Модель не держатся за ссылку на докладчика. Когда представление умирает, ведущий уходит с ним.

Самое замечательное в докладчиках состоит в том, что вы можете инкапсулировать просто того, что нужно представлению. Интерфейс для докладчика почти полностью определяется представлением. Вы даже можете делать такие вещи, как создание разных докладчиков для разных представлений и заполнять их всех одним интерфейсным методом, например так: Presenter.PopulateWith(model, controller). Это дает вам прекрасное место для выполнения всей логики представления (даты в строках, логины без . и т. Д.) Без загрязнения вашей прекрасной модели. И вы получите свою слабую ссылку бесплатно!

Это очень похоже на шаблон MVVM, который теперь используется в идиоматическом WPF. Хорошо работает на Java, в том числе и в Web. Надеюсь, это даст вам некоторые идеи.

0 голосов
/ 22 июля 2010

... но я хотел бы, чтобы Controllers были анонимными внутренними классами класса View, и в этом случае экземпляр Controller имеет неявную строгую ссылку на экземпляр View.

Это просто не сработает ... на основании диаграмм в вопросе.

Регулярная ссылка в Model на Controller и другая в Controller на View будетдостаточно, чтобы означать, что View сильно достижимо.В результате слабая ссылка в Controller на View не будет нарушена ... до тех пор, пока сам Model не станет пригодным для сборки мусора.

Поскольку анонимный внутренний класс никогда не может бытьstatic, у вас нет разумного выбора (*), кроме как сделать Контроллер статическим вложенным классом или не вложенным классом.

Другой альтернативой будет сделать ссылку из Модели на Контроллерслабая ссылка.

(* На самом деле есть хитрость, которая может сработать ... хотя это слишком ужасно, чтобы упоминать. Вы можете выяснить, какое имя скрытого атрибута содержитссылка объекта Controller на его родительский объект, и, возможно, используйте отражение, чтобы найти Field, а затем используйте его для установки атрибута null.)


EDIT

Это то, что JLS говорит об анонимных классах - JLS 15.9.1

Анонимный класс никогда не бывает абстрактным (§8.1.1.1).Анонимный класс всегда является внутренним классом (§8.1.3); никогда не бывает статичным (§8.1.1, §8.5.2).Анонимный класс всегда неявно является окончательным (§8.1.1.2).

Мне трудно согласовать это с комментарием ОП ...

0 голосов
/ 22 июля 2010

Я думаю, вы на правильном пути.Я вижу два возможных решения для правильного восстановления представлений:

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

  2. Удалить сильную ссылку в контроллере.Контроллер может либо использовать WeakReference для удержания представления, которое необходимо проверять при каждом доступе, либо вместо этого передавать контроллеру реализацию View, которая делегируется вашему реальному представлению, удерживая его через слабую ссылку.Если ссылка была восстановлена ​​(является нулевой), то вызов метода является неоперативным.

0 голосов
/ 22 июля 2010

Здесь у вас есть отличная реализация шаблона MVC. Вероятно, есть решение вашей проблемы.

...