Смоделировать реальный мир или надлежащий мир ООП? Или оба?

Используйте шпиона ++ для наблюдения то, какое сообщение WM_COMMMAND отправляется, когда Вы нажимаете F5 в Windows Explorer или находите, какое сообщение меню используется для представления/обновления

Тогда использование FindWindow для получения окна проводника, которое Вы хотите и отправляете, WM_COMMAND записал ранее и т.д. сообщение к нему.

Это - интересный способ управлять всеми видами Windows-программ.

8
задан Pup 30 August 2009 в 17:56
поделиться

11 ответов

This is always a struggle for me -- do I defy proper object-oriented design (e.g. option 1) or do I use an implementation that seems counterintuitive to the real world (e.g. option 2)?

I don't think that the purpose of object-orientation is to model the real world.

I think that a (the?) reason why an OO model often follows a model of the real-world is that the real-world doesn't change much: and therefore choosing the real world as the model means that the software won't change much, i.e. it will be inexpensive to maintain.

Fidelity to the real world isn't a design goal in itself: instead you should be trying for designs which maximize other metrics, e.g. simplicity.

The 'objects' in 'object orientation' are software objects, not necessarily real-world objects.

8
ответ дан 5 December 2019 в 05:34
поделиться

MVC concept is a good practice in general and should still be used in game designs as a general principle. But by the interactive nature of the game UI, you should also look into event based architecture. MVC does not contradict with event based architecture if designed carefully. (PureMVC as an example.)

I suggest you to use observable pattern on all display objects so they can all listen/fire events. This will save you a lot of headache later on. When your code base gets more complex, you will eventually HAVE TO use more decoupling techniques such as your option 2 describes. Also mediator pattern will help as well.

Edit:

Mediator Pattern is generally a good way to organize application level events.

Here is a blog about using MVC, events and mediators in game programming:

http://ezide.com/games/writing-games.html

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

Второй метод - это явно более идиоматический способ передачи вещей во Flash. В AS3 модель событий встроена прямо в EventDispatcher , и все DisplayObjects наследуются от нее. Это означает, что любой Bitmap , Sprite или MovieClip сразу узнает, если по нему щелкнули.

Воспринимайте Flash Player как свой контроллер. Когда я делаю MVC во Flash, я почти никогда не пишу контроллер, потому что Flash Player делает это за вас. Вы тратите циклы на определение того, что было нажато, когда Flash Player уже знает об этом.

var s:Sprite = new Sprite();
s.addEventListener(MouseEvent.CLICK, handleMouseClick);
function handleMouseClick(event:MouseEvent):void
{
    // do what you want when s is clicked
}

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

Наконец, причина, по которой я предлагаю, не имеет ничего общего с некоторыми концепциями OOD или OOP в Башне из слоновой кости. Подобные принципы существуют, чтобы помочь вам не ограничивать вас. Когда дело доходит до прагматики, выбирайте самое простое решение, которое не вызовет у вас головной боли. Иногда это означает выполнение ООП, иногда - функциональность, иногда - необходимость.

Подобные принципы существуют, чтобы помочь вам не ограничивать вас. Когда дело доходит до прагматики, выбирайте самое простое решение, которое не вызовет у вас головной боли. Иногда это означает выполнение ООП, иногда - функциональность, иногда - необходимость.

Подобные принципы существуют, чтобы помочь вам не ограничивать вас. Когда дело доходит до прагматики, выбирайте самое простое решение, которое не вызовет у вас головной боли. Иногда это означает выполнение ООП, иногда - функциональность, иногда - необходимость.

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

Why not go with Option 3, which is simlar to Option 1?

  • Controller calls player's function:
    Controller listens for mouse events. When a mouse click occurs anywhere onscreen, the controller searches all objects under the point that was clicked. If one of the objects implements IClickable or inherits Clickable (or whatever), then call its appropriate function (or fire an event, whichever is appropriate).
5
ответ дан 5 December 2019 в 05:34
поделиться

This often comes to preference. Logical games design is, very frequently, at odds with good OOP design. I lean towards what makes sense in the scope of the game universe, but there's absolutely no right answer to the question and every single problem should be taken on its own merit.

This is somewhat similar to arguing about the pros and cons of camel casing.

1
ответ дан 5 December 2019 в 05:34
поделиться

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

все эти передние контроллеры просто преобразуют события, и, таким образом, полностью независимы от того, как логика приложения реагирует на определенные события ... логика приложения, с другой стороны, отделена от этих фронт-контроллеров ... "протокол" - это предопределенный набор событий ... когда он доходит до механизма уведомления, решать вам,используете ли вы диспетчеризацию событий AS3 для получения событий от фронтальных контроллеров к контроллерам приложений, или создаете ли вы их на основе определенного интерфейса, который они будут вызывать ...

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

так что да, это определенно версия 1 ... в данном случае , переднему контроллеру для вводов мыши необходимо знать только список отображения и иметь логику о том, когда какое событие отправлять ... а контроллер приложения должен иметь возможность обрабатывать какое-то событие PlayerEvent.SELECT в этом случае ... (если позже вы решите использовать какой-то учебный режим или что-то еще,вы можете просто перемещать фальшивую мышь и отправлять это событие в случае фальшивых щелчков, или вы можете просто повторить все в каком-то виде воспроизведения, или вы можете использовать это для записи макросов, когда речь идет не об играх ... просто чтобы указать на некоторые сценарии, в которых это разделение полезно)

надеюсь, что это поможет ...;)

1
ответ дан 5 December 2019 в 05:34
поделиться

Согласно Применение UML и шаблонов (Крейг Ларман), пользовательский интерфейс (события мыши) никогда не должен взаимодействовать с классами вашего приложения, то есть пользовательский интерфейс никогда не должен напрямую управлять бизнес-логикой.

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

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

2
ответ дан 5 December 2019 в 05:34
поделиться

Я не согласен с вашей оценкой этих двух вариантов. Вариант 2 хуже объектно-ориентированного подхода, поскольку он тесно связывает объект Player с конкретной реализацией пользовательского интерфейса. Что произойдет, если вы захотите повторно использовать свой класс Player где-нибудь за кадром или где используется интерфейс без мыши?

Однако вариант 1 все еще можно улучшить. Предыдущее предложение об использовании интерфейса iClickable или суперкласса Clickable является огромным улучшением, поскольку оно позволяет реализовать несколько типов интерактивных объектов (не только Player) без необходимости предоставлять контроллеру огромный список «Является ли объект этим классом? это тот класс? "

Ваше главное возражение против варианта 1 состоит в том, что он проверяет свойство Player "clickable", которое, по вашему мнению, нарушает инкапсуляцию. Это не так. Он проверяет свойство, которое определено как часть общедоступного интерфейса Player. Это ничем не отличается от вызова метода из общедоступного интерфейса.

Да, я понимаю, что в данный момент свойство "clickable" реализовано таким образом, что это простой метод получения, который не делает ничего, кроме запроса внутреннего состояния игрока, но не обязательно . Свойство может быть переопределено завтра, чтобы определить его возвращаемое значение совершенно другим способом без ссылки на внутреннее состояние, и, пока оно все еще возвращает логическое значение (т. Е. Открытый интерфейс остается прежним), код с использованием Player.clickable будет все еще работает нормально. В этом разница между собственностью и непосредственной проверкой внутреннего состояния - и это очень большая разница.

Если это по-прежнему вызывает у вас беспокойство, достаточно просто избавиться от необходимости проверять контроллер Player.clickable: просто отправьте событие щелчка каждому объекту под мышью, который реализует iClickable / спускается с Clickable. Если объект не находится в состоянии щелчка, когда он получает щелчок, он может просто проигнорировать его.

1
ответ дан 5 December 2019 в 05:34
поделиться

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

Это не должно останавливать вас от поиска других решений. Но старайтесь всегда придерживаться языковой идиомы. ООП не переносится в реальную жизнь в отношениях 1 к 1, и он не особенно хорош в имитации. Наглядным примером является классическая взаимосвязь прямоугольника и квадрата объекта, о которой вы, вероятно, уже все знаете. В реальной жизни квадрат - это прямоугольник. В ООП (или, по крайней мере, в собственном ООП) это отношение плохо транслируется в отношения, производные от базы. Итак, вы чувствуете необходимость отказаться от реальной эмуляции, потому что идиома языка говорит выше. Либо это, либо мир боли, когда вы начинаете серьезно реализовывать прямоугольник и квадрат или позже хотите внести в них изменения.

1
ответ дан 5 December 2019 в 05:34
поделиться

Мне всегда приходится нелегко: бросаю вызов правильному объектно-ориентированному дизайну (например, вариант 1) или использую реализацию, которая кажется противоречащей реальному миру (например, вариант 2) ?

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

Объектно-ориентированный дизайн - это интерфейсы, объекты, которые их реализуют, и взаимодействие между этими объектами (сообщениями, которые они передают между собой). Интерфейсы - это договорные соглашения между двумя компонентами, модулями или подсистемами программного обеспечения. ОО-дизайн имеет много качеств, но наиболее важным для меня является замещение. Если у меня есть интерфейс, то код реализации лучше его придерживается. Но что более важно, если реализация поменяется местами, тогда новая реализация будет лучше придерживаться этого. И наконец, если реализация должна быть полиморфной, то различные стратегии и состояния полиморфной реализации лучше соответствуют ей.

Пример 1

В математике квадрат является прямоугольником . Похоже, неплохо унаследовать класс Square от класса Rectangle. Вы делаете это, и это ведет к разорению. Почему? Потому что ожидания или убеждения клиента были нарушены. Ширина и высота могут меняться независимо друг от друга, но Square нарушает это соглашение. У меня был прямоугольник размера (10, 10), и я установил ширину на 20. Теперь я думаю у меня есть прямоугольник размера (20, 10), но фактический экземпляр - квадратный экземпляр с размерами ( 20, 20) и меня, клиента, ждет настоящий большой сюрприз. Итак, теперь у нас есть нарушение принципа наименьшего удивления.

Теперь у вас есть ошибочное поведение, которое приводит к тому, что клиентский код становится сложным, как будто для обхода ошибочного поведения необходимы операторы. Вы также можете найти свой клиентский код, требующий, чтобы RTTI обошел ошибочное поведение, проверив типы conrete (у меня есть ссылка на Rectange, но я должен проверить, действительно ли это экземпляр Square).

Пример 2

In настоящие животные могут быть плотоядными или травоядными. В реальной жизни мясо и овощи - это пища. Таким образом, вы можете подумать, что иметь класс Animal в качестве родительского класса для разных типов животных - хорошая идея. Вы также думаете, что иметь родительский класс FoodType для классов Meat и Vegetable - это хорошая идея. Наконец, у вас есть класс Animal sport с методом eat (), , который принимает FoodType в качестве формального аргумента.

Все компилируется, проходит статический анализ и связывает. Вы запускаете свою программу. Что происходит во время выполнения, когда подтип Animal, скажем, травоядное животное, получает FoodType, который является экземпляром класса Meat? Добро пожаловать в мир совпадения и противоречия. Это проблема многих языков программирования. Это также интересная и сложная проблема для разработчиков языков.

В заключение ...

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

Посмотрите Шаблоны анализа Мартина Фаулера. Там вы увидите, что движет его объектно-ориентированными проектами. В основном это основано на том, как его клиенты (медики, финансовые люди и т. Д.) Выполняют свои повседневные задачи. Он пересекается с реальностью, но не основан на реальности и не движется ею.

2
ответ дан 5 December 2019 в 05:34
поделиться

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

IClickHandler также может быть выбран на основе других критериев (IOW объект не выбирает сам IClickHandler при регистрации, некоторые его выбирает другой алгоритм). Хорошим примером может служить то, что всем объектам NPC предоставляется IClickHandler, который пересылает щелчки, в то время как все деревья получают IClickHandler, который не пересылает щелчки.

Как минимум у вас может быть 3 обработчика, реализующих интерфейс: AlwaysClickable, NeverClickable, ToggledClickable

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

Также обратите внимание, что лучше не просто придерживаться каких-либо принципов. Делайте то, что лучше всего, учитывая обстоятельства, когда вы пишете код. Если вы пишете клон Тетриса, тот факт, что Вариант 1 «нарушает» принципы ООП, совершенно не имеет значения.

1
ответ дан 5 December 2019 в 05:34
поделиться