Разделение классов от пользовательского интерфейса

27

Какова лучшая практика, когда речь идет о написании классов, которые, возможно, должны знать о пользовательском интерфейсе. Разве класс, не знающий, как рисовать себя, не нарушит некоторые лучшие практики, так как это зависит от того, каков пользовательский интерфейс (консоль, графический интерфейс и т. Д.)?

Во многих книгах по программированию я встречал пример «Shape», который показывает наследование. Форма базового класса имеет метод draw (), который переопределяет каждая форма, такая как круг и квадрат. Это учитывает полиморфизм. Но разве метод draw () не сильно зависит от пользовательского интерфейса? Если мы напишем этот класс, скажем, Win Forms, то мы не сможем повторно использовать его для консольного приложения или веб-приложения. Это верно?

Причина этого вопроса в том, что я всегда застреваю и зацикливаюсь на том, как обобщать классы, чтобы они были наиболее полезными. Это на самом деле работает против меня, и мне интересно, если я "слишком стараюсь".

Пит
источник
Почему вы хотите отделить? Потому что вы слышали, что это правильно, или у вас есть другие причины?
SoylentGray
2
Весь «класс, умеющий рисовать сам» - это просто ужасный, древний пример, который я хотел бы, чтобы он исчез. Особенно в стеке программиста игры =)
Патрик Хьюз
2
@ Честно говоря, у меня мало опыта за пределами школы. Я читал книги, и мне искренне нравится изучать и читать новые вещи о шаблонах проектирования и лучших практиках. Так что да, вы можете сказать, что я слышал, что разделение это хорошо, но это также имеет смысл. Я хочу написать код, который я могу использовать, например, для настольного приложения WinForms, затем взять этот код и максимально использовать его для веб-сайта или даже для приложения silverlight.
Пит
@ Пит - это хороший ответ.
SoylentGray
2
@ Патрик: если честно, если вы пишете Shapeкласс, то вы, вероятно, пишете сам графический стек, а не записываете клиент в графический стек.
Кен Блум,

Ответы:

13

Какова лучшая практика, когда речь идет о написании классов, которые, возможно, должны знать о пользовательском интерфейсе. Разве класс, не знающий, как рисовать себя, не нарушит некоторые лучшие практики, так как это зависит от того, каков пользовательский интерфейс (консоль, графический интерфейс и т. Д.)?

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

Во многих книгах по программированию я встречал пример «Shape», который показывает наследование. Форма базового класса имеет метод draw (), который переопределяет каждая форма, такая как круг и квадрат. Это учитывает полиморфизм. Но разве метод draw () не сильно зависит от пользовательского интерфейса?

Опять не обязательно. Если вы можете создать интерфейс (drawPoint, drawLine, установить Color и т. Д.), Вы можете в значительной степени передать любой контекст для рисования чего-либо на фигуре, например в конструкторе фигуры. Это позволило бы фигурам рисовать себя на консоли или любом заданном холсте.

Если мы напишем этот класс, скажем, Win Forms, то мы не сможем повторно использовать его для консольного приложения или веб-приложения. Это верно?

Ну, это правда. Если вы напишите UserControl (не класс в целом) для Windows Forms, вы не сможете использовать его с консолью. Но это не проблема. Почему вы ожидаете, что UserControl для Windows Forms будет работать с любой презентацией? UserControl должен делать одну вещь и делать это хорошо. Это связано с определенной формой представления по определению. В конце концов, пользователю нужно что-то конкретное, а не абстракция. Это может быть только частично верно для фреймворков, но для приложений конечного пользователя это так.

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

Причина этого вопроса в том, что я всегда застреваю и зацикливаюсь на том, как обобщать классы, чтобы они были наиболее полезными. Это на самом деле работает против меня, и мне интересно, если я "слишком стараюсь".

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

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

Изменить: Если вы хотите узнать больше об архитектуре и методах проектирования, которые могут предоставить лучшие практики, я предлагаю вам прочитать ответ @Catchops и прочитать о методах SOLID в Википедии.

Кроме того, для начала я всегда рекомендую следующую книгу: Head First Design Patterns . Это поможет вам понять методы абстрагирования / разработки ООП, в большей степени, чем книга GoF (что отлично, просто не подходит новичкам).

сокол
источник
1
Хороший ответ, но экстремальные программисты не «ставят абстракции там, где мы ожидаем, что что- то изменится». Мы помещаем в абстракциях , где вещи являются изменяющимися, высыхать код.
Кевин Клайн
1
@kevin cline - это круто, если вы не разрабатываете общедоступную библиотеку с API, который должен соответствовать предыдущему поведению и интерфейсам.
Магнус Вольффелт
@Magnus - да, разработка библиотеки на нескольких языках, планирование обратной двоичной совместимости - это сложно. Один вынужден писать все виды ненужного в настоящее время кода, чтобы учесть будущее расширение. Это может быть разумно для языков, которые компилируются в металл. Это глупо для языков, которые компилируются в виртуальную машину.
Кевин Клайн
19

Вы определенно правы. И нет, вы "просто отлично пытаетесь" :)

Читайте о принципе единой ответственности

Ваша внутренняя работа в классе и то, как эта информация должна быть представлена ​​пользователю, являются двумя обязанностями.

Не бойтесь разъединять занятия. Редко проблема в слишком большой абстракции и развязке :)

Два очень важных шаблона - это модель – представление – контроллер для веб-приложений и модель View ViewModel для Silverlight / WPF.

Борис Янков
источник
1
+1 Вы даже можете использовать MVC для не-веб-приложений, по крайней мере, это поможет вам мыслить так, чтобы четко определить обязанности.
Патрик Хьюз
MVVM является silimar для MVC. MVC в основном для приложений без сохранения состояния, таких как веб-приложения.
Борис Янков
3
-1 По моему опыту, одной из наиболее распространенных проблем является преждевременное обобщение и чрезмерная инженерия в целом.
dietbuddha
3
Сначала вы должны знать, как спроектировать что-то, чтобы чрезмерно спроектировать это. По моему опыту, люди, которые «плохо разбираются» в программном обеспечении, гораздо чаще.
Борис Янков
В то время как я ценю усилия по улучшению дизайна программного обеспечения, замена вызова интерфейса вызовом класса ничего не разделяет семантически. Рассмотрим, что происходит при использовании динамически типизированного языка. Слишком много внимания уделяется поверхностному (синтаксическому) разделению, и мало - истинному разделению - в рекомендациях, представленных в разделе «Программирование обмена стеками».
Фрэнк Хилман
7

Я часто использую MVVM, и, по моему мнению, класс бизнес-объектов никогда не должен знать ничего о пользовательском интерфейсе. Конечно, им может понадобиться знать SelectedItem, или IsChecked, или IsVisible, и т. Д., Но эти значения не обязательно должны быть привязаны к какому-либо конкретному интерфейсу и могут быть общими свойствами класса.

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

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

Рейчел
источник
5

Есть много проверенных и настоящих шаблонов проектирования, которые были разработаны за эти годы, чтобы точно соответствовать тому, о чем вы говорите. Другие ответы на ваш вопрос касались принципа единой ответственности - который является абсолютно действительным - и что, по-видимому, движет вашим вопросом. Этот принцип просто утверждает, что класс должен делать одну вещь ХОРОШО. Другими словами, повышение Cohesion и понижение Coupling - вот что такое хороший объектно-ориентированный дизайн - делает ли класс одно дело хорошо и не имеет много зависимостей от других.

Ну ... вы правы, заметив, что если вы хотите нарисовать круг на iPhone, он будет отличаться от рисунка на ПК под управлением Windows. Вы ДОЛЖНЫ иметь (в данном случае) конкретный класс, который рисует одну лунку на iPhone, а другой - одну лунку на ПК. Вот где основной ОО-принцип наследования, который разбивают все эти примеры форм. Вы просто не можете сделать это только по наследству.

Именно здесь вступают интерфейсы - как утверждает «Бригада четырех» (ДОЛЖНА ПРОЧИТАТЬ) - Всегда отдавайте предпочтение реализации, а не наследованию. Другими словами, используйте интерфейсы для объединения архитектуры, которая может выполнять различные функции разными способами, не полагаясь на жестко закодированные зависимости.

Я видел Referece к ТВЕРДЫМ принципам. Это здорово. «S» - это принцип единственной ответственности. НО, «D» означает инверсию зависимости. Здесь можно использовать шаблон Inversion of Control (Dependency Injection). Он очень мощный и может использоваться для ответа на вопрос о том, как спроектировать систему, которая может нарисовать круг для iPhone, а также для ПК.

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

Это просто быстрый высокоуровневый ответ на вопрос, который заслуживает более подробного ответа. Я призываю вас заглянуть в эти паттерны. Можно найти более конкретную реализацию этих шаблонов, а также хорошо известные имена MVC и MVVM.

Удачи!

Catchops
источник
Мне нравится, когда кто-то отрицает что-то, не комментируя, почему (сарказм, конечно). Принципы, которые я изложил, верны - пожалуйста, встаньте и скажи почему.
Catchops
2

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

Разве класс, не знающий, как рисовать себя, не нарушит некоторые лучшие практики, так как это зависит от того, каков пользовательский интерфейс (консоль, графический интерфейс и т. Д.)?

В этом случае вы все еще можете использовать MVC / MVVM и внедрять различные реализации пользовательского интерфейса, используя общий интерфейс:

public interface IAgnosticChartDrawing
{
   public void Draw(ChartProperties chartProperties);
   event EventHandler ChartPanned;
}

public class GuiChartDrawer : UserControl, IAgnosticChartDrawing
{
    public void Draw(ChartProperties chartProperties)
    {
        //GDI, GTK or something else...
    }

    //Implement event based on mouse actions
}

public class ConsoleChartDrawer : IAgnosticChartDrawing
{
    public void Draw(ChartProperties chartProperties)
    {
        //'Draw' using characters and symbols...
    }

    //Implement event based on keyboard actions
}

IAgnosticChartDrawing guiView = new GuiChartDrawer();
IAgnosticChartDrawing conView = new ConsoleChartDrawer();

Model model = new FinancialModel();

SampleController controllerGUI = new SampleController(model, guiView);
SampleController controllerConsole = new SampleController(model, conView);

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

логово
источник
2

Для этого есть разные шаблоны: MVP, MVC, MVVM и т. Д.

Хорошая статья Мартина Фаулера (известное имя) для чтения - GUI Architectures: http://www.martinfowler.com/eaaDev/uiArchs.html

MVP пока не упоминается, но на него, безусловно, стоит упомянуть: взгляните на это.

Это шаблон, предложенный разработчиками Google Web Toolkit для использования, он действительно аккуратный.

Вы можете найти реальный код, реальные примеры и обоснование того, почему этот подход полезен здесь:

http://code.google.com/webtoolkit/articles/mvp-architecture.html

http://code.google.com/webtoolkit/articles/mvp-architecture-2.html

Одно из преимуществ использования этого или аналогичных подходов, которое здесь недостаточно подчеркивается, - это тестируемость! В большинстве случаев я бы сказал, что это главное преимущество!

Андреа Зилио
источник
1
+1 за ссылки. Я читал аналогичную статью на MSDN о MVVM, и эти статьи Google намного лучше, хотя и по несколько иному шаблону.
Пит
1

Это одно из мест, где ООП терпит неудачу с задачей абстракции. ООП полиморфизм использует динамическую диспетчеризацию по одной переменной ('this'). Если полиморфизм был основан на Shape, то вы не можете отправить полиморфно-союзников на рендерер (консоль, графический интерфейс и т. Д.).

Рассмотрим систему программирования, которая может распределяться по двум или более переменным:

poly_draw(Shape s, Renderer r)

и также предположим, что система может дать вам способ выразить poly_draw для различных комбинаций типов Shape и Renderer. Тогда было бы легко придумать классификацию форм и средств визуализации, верно? Проверка типов как-то поможет вам понять, есть ли комбинации формы и рендера, которые вы, возможно, пропустили.

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

Ritesh
источник
1

... не зависит ли метод draw () от интерфейса пользователя? Если мы напишем этот класс, скажем, Win Forms, то мы не сможем повторно использовать его для консольного приложения или веб-приложения. Это верно?

Выше звучит правильно для меня. Насколько я понимаю, можно сказать, что это означает относительно тесную связь между Controller и View с точки зрения шаблона проектирования MVC. Это также означает, что для переключения между desktop-console-webapp необходимо будет соответственно переключить Controller и View в виде пары - только модель остается неизменной.

... Я постоянно зацикливаюсь на том, как обобщать классы, чтобы они были наиболее полезными.

Что ж, мое текущее мнение о том, что соединение между View-Controller, о котором мы говорим, в порядке, и даже более, оно довольно модно. в современном дизайне.

Хотя год или два назад я тоже чувствовал себя неуверенно по этому поводу. Я передумал после изучения дискуссий на форуме Sun по шаблонам и ОО-дизайну.

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

комар
источник
1

Но разве метод draw () не сильно зависит от пользовательского интерфейса?

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

Вопрос для меня с точки зрения связи: кто / что должен зависеть от этого типа информации и от какой степени детализации (например, абстрактной)?

Абстрагирование возможностей рисования / рендеринга

Потому что, если код рисования более высокого уровня зависит только от чего-то очень абстрактного, эта абстракция может работать (путем замены конкретных реализаций) на всех платформах, на которые вы собираетесь ориентироваться. В качестве надуманного примера, некоторые очень абстрактныеIDrawer интерфейсы могут быть реализованы как в консоли, так и в GUI API, чтобы выполнять такие вещи, как формы графиков (реализация консоли может обрабатывать консоль как некое «изображение» 80xN с использованием ASCII-графики). Конечно, это надуманный пример, поскольку обычно это не то, что вам нужно, это обрабатывать вывод консоли как буфер изображений / кадров; как правило, большинству пользователей требуется больше текстовых взаимодействий в консолях.

Еще один вопрос: насколько легко создать стабильную абстракцию? Потому что это может быть легко, если все, на что вы нацеливаетесь, - это современные API-интерфейсы GUI для абстрагирования основных возможностей рисования фигур, таких как построение линий, прямоугольников, путей, текста и тому подобное (просто простая растеризация 2D ограниченного набора примитивов) с одним абстрактным интерфейсом, который может быть легко реализован для них через различные подтипы с минимальными затратами. Если вы можете эффективно спроектировать такую ​​абстракцию и реализовать ее на всех целевых платформах, то я бы сказал, что это гораздо меньшее зло, если даже вообще не зло, для формы или элемента управления графическим интерфейсом или что-то еще, чтобы знать, как рисовать себя, используя такую абстракция.

Но, скажем, вы пытаетесь абстрагироваться от мрачных деталей, которые различаются между Playstation Portable, iPhone, XBox One и мощным игровым ПК, в то время как вы должны использовать самые передовые технологии 3D-рендеринга / затенения в реальном времени на каждом из них. , В этом случае попытка придумать один абстрактный интерфейс для абстрагирования деталей рендеринга, когда базовые аппаратные возможности и API-интерфейсы настолько дико изменяются, почти наверняка приведет к огромному времени на разработку и перепроектирование, высокую вероятность повторяющихся изменений дизайна с непредвиденными открытия, а также решение с наименьшим общим знаменателем, которое не в состоянии использовать полную уникальность и мощь базового оборудования.

Обеспечение зависимости от стабильных, «легких» конструкций

В моей области я в этом последнем сценарии. Мы нацелены на множество разного оборудования с принципиально разными базовыми возможностями и API, и попытаться придумать одну абстракцию рендеринга / рисования, чтобы управлять ими всеми, безгранично безнадежно (мы можем стать всемирно известными, просто делая это эффективно, как в игре сменщик в отрасли). Поэтому последнее , что я хочу в моем случае это как аналоговая Shapeили Modelили Particle Emitterчто умеет рисовать себя, даже если он выражает , что рисунок на самом высоком уровне и , возможно , наиболее абстрактный способ ...

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

Сложный Зависит от Легко, Не Легко Зависит от Трудно

Вместо этого мы делаем так, чтобы зависимости перетекли в вещи, которые легко спроектировать. Гораздо проще спроектировать абстрактную «Модель», которая просто сфокусирована на хранении таких вещей, как многоугольники и материалы, и придать ей правильную конструкцию, чем спроектировать абстрактный «Рендерер», который можно эффективно реализовать (с помощью заменяемых конкретных подтипов) для обслуживания чертежей единообразно запрашивает аппаратное обеспечение, такое же, как PSP от ПК.

введите описание изображения здесь

Таким образом, мы инвертируем зависимости от вещей, которые сложно спроектировать. Вместо того, чтобы заставлять абстрактные модели знать, как рисовать себя в дизайне абстрактного рендерера, от которого они все зависят (и нарушать свои реализации, если этот дизайн меняется), у нас вместо этого есть абстрактный рендерер, который знает, как рисовать каждый абстрактный объект в нашей сцене ( модели, излучатели частиц и т. д.), и поэтому мы можем затем реализовать подтип рендерера OpenGL для ПК, например RendererGl, другой для PSP RendererPsp, другой для мобильных телефонов и т. д. В этом случае зависимости стремятся к стабильным проектам, их легко получить правильно, от рендера до различных типов объектов (моделей, частиц, текстур и т. д.) в нашей сцене, а не наоборот.

введите описание изображения здесь

  • Я использую «стабильность / нестабильность» в несколько ином смысле, чем метрика афферентных / эфферентных связей дяди Боба, которая, насколько я понимаю, больше измеряет трудность изменений Я говорю больше о «вероятности необходимости изменений», хотя его метрика стабильности там полезна. Когда «вероятность изменения» пропорциональна «легкости изменения» (например, вещи, которые, скорее всего, потребуют изменений, имеют самую высокую нестабильность и афферентные связи из метрики дяди Боба), тогда любые такие вероятные изменения дешевы и не требуют вмешательства , требующий только замены реализации, не касаясь каких-либо центральных конструкций.

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

Принцип единой ответственности

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

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

Гордость разработчика

Я упоминаю об этом, потому что, по моему опыту, это часто является самым большим препятствием на пути направления зависимостей к вещам, которые легче спроектировать. Разработчикам очень легко стать немного амбициозными и сказать: «Я собираюсь разработать кроссплатформенную абстракцию рендеринга, чтобы управлять ими всеми, я решу, что другие разработчики тратят месяцы на портирование, и я собираюсь получить это правильно, и это будет работать как волшебство на каждой платформе, которую мы поддерживаем, и использовать самые современные методы рендеринга на каждой; я уже думал об этом ».В этом случае они отказываются от практического решения, которое состоит в том, чтобы избежать этого и просто изменить направление зависимостей и перевести то, что может быть чрезвычайно дорогостоящим, и повторяющиеся центральные изменения проекта в просто дешевые и локальные повторяющиеся изменения в реализации. В разработчиках должен быть какой-то инстинкт «белого флага», чтобы сдаться, когда что-то слишком сложно спроектировать до такого абстрактного уровня, и пересмотреть всю свою стратегию, в противном случае их ждет много горя и боли. Я бы посоветовал перенести такие амбиции и боевой дух в современные реализации, которые легче спроектировать, чем перенести такие покоряющие мир амбиции на уровень дизайна интерфейса.

Энергия Дракона
источник
1
Я не могу понять идею «инвертировать зависимости от вещей, которые трудно спроектировать», вы говорите только о наследовании? Используя пример PSP / OpenGL, вы имеете в виду, что вместо создания a OpenGLBillboardвы создадите a, OpenGLRendererкоторый умеет рисовать любой тип IBillBoard? Но будет ли он делать это путем делегирования логики IBillBoardили будет иметь огромные переключатели или IBillBoardтипы с условными выражениями ? Это то, что мне трудно понять, потому что это совсем не похоже на ремонтопригодность!
Стив Chamaillard
@SteveChamaillard Разница, скажем, в том, что PSP (ограниченное аппаратное обеспечение) должно обрабатывать объемные примитивы с использованием прозрачности screendoor старой школы и другого порядка оценки визуализации: digitalrune.github.io/DigitalRune-Documentation/media/… . Когда у вас есть один центральный RendererPspобъект, который знает высокоуровневые абстракции вашей игровой сцены, он может затем делать всю магию и сальто, необходимые для рендеринга таких вещей способом, который выглядит убедительно на PSP ....
Dragon Energy
Принимая во внимание, что если у вас были такие объемные примитивы, запрашивающие рендеринг самих себя, либо их операции настолько высокоуровневы, что они в основном задают себя для рендеринга (что не имеет значения, кроме обходной избыточности и дальнейшего связывания), либо абстракция рендерера не способна на самом деле делать вещи наиболее эффективным способом на PSP (по крайней мере, без бэкфлипов, что не нужно было бы делать, если зависимости были инвертированы).
Энергия Дракона,
1
Хорошо, я думаю, что получил это сейчас. По сути, вы говорите, что такие проблемы (например, аппаратные средства) настолько высоки, что сделать объекты низкого уровня, такие как BillBoardзависимость, будет действительно трудно? Принимая во внимание, что IRendererуровень a уже высок и может зависеть от этих проблем с гораздо меньшими проблемами?
Стив Chamaillard
1
С передовыми задачами рендеринга на разнородных платформах, несопоставимыми аппаратными возможностями слишком сложно спроектировать что-то, где я босс, и сказать ему, что делать. Мне намного легче сказать: «Эй, я облачный / туманный предмет с сероватыми водянистыми частицами, подобными этому, и стараюсь, чтобы я выглядел хорошо, пожалуйста, не бери мою шею, которую я не побрил в последнее время», и пусть рендерер выяснит, как сделать меня максимально красивым и в реальном времени, учитывая ограничения, с которыми он работает. Любая попытка сказать ему, что делать, почти наверняка приведет к контрпродуктивному пути.
Dragon Energy