Комментарии 7
SOLID для начинающих
Лучше бы вместо принципов программирования объясняли бы технологию программирования. Например, как правильно организовывать интерфейс пользователя в программе обучения иностранному языку?
Там известные принципы мало чем помогают, ООП – еще немного рулит. А под GUI нужно еще выстраивать программную логику, поскольку логика сильно зависит от «графики». Чтобы оптимизировать логику, нужно оптимизировать взаимодействие графических примитивов. А там не все очевидно, тем более, что «графика» очень часто не своя, а чужая.
Я себе чуть голову не сломал, когда занимался разработкой соответствующего алгоритма. Одних только блок-схем нарисовал, для себя, более двадцати. И в текстовом виде описывал алгоритм десятки раз, с учетом его фрагментов. В итоге, проблему решил и опубликовал в последних статьях, но главный принцип программирования, который я вынес оттуда, это: «Метод здравого смысла».
А все эти солиды, киссы, дрюи и тому подобное интеллектуальное бла-бла-бла, по большому счету, мало что дают. Анализируйте, внимательно, хороший опенсорсный код и развивайте свой здравый смысл, и будет вас счастье!
скорее всего шейдерами в рамках Юнити, но вообще можно проще обойтись надо помимо отрисовки еще разобраться с тем как работает процесс, потомучто игра это процесс, надо чтобы процесс был зарегестрирован и приложение получало валидные состояния, а не висело в топе поидее, потомучто на простое будет нагрузка и ну надо разобраться как работает планировщик виндовс всё таки, и как это дело устроено в Юнити
просто Delay(потомучто надо чтобы от процесса(относительно планировщика) было управление текущим состоянием процесса, а не просто пропуск кеш линий) может не помочь процесс может получить пограничное состояние со всеми вытекающими, соответственно отсюда тянется ветка к изучению как это устроено
Статья, как водится, пустовата.
Возможно полезнее объяснять, не что делать, но почему.
Вот, например, другой разбор.
Не то, как вам следует использовать SOLID, а как его использовала сама Unity и где можно поучиться.
Single responsibility principle - про единую ответственность.
Это необходимо для организации, чтобы код был написан так, чтобы смежные изменения затрагивали ограниченное количество файлов, а не расползались по системе. Важно тут не то, что функция/класс делает что-то одно, а то, что она делает это в интересах одной цели.
Unity великолепно следует этому принципу и поставила его во главу угла. Любая сцена состоит из объектов и компонентов на них. Компоненты - буквальное воплощение принципа. Каждый имеет свою задачу и независим от других. Если ошибка будет в модуле, ответственном за текст - вам не нужно менять компоненты, ответственные за физику.
В некоторых случаях компоненты могут быть связаны, но даже тут они сгруппированы или имеют прямые ссылки друг на друга. К примеру кнопка явно использует графический компонент (например картинку) как свою визуализацию.
Вам следует стараться писать ваши логические компоненты в той же парадигме, насколько это возможно.
Иногда для сложных систем этого недостаточно - многие объекты должны знать друг о друге. На это призваны ответить различные паттерны организации и принципы, которые выходят за рамки этого принципа, тем не менее он остается полезен.
Open close principle - есть много трактовок этого принципа, но в общем случае это можно понимать как "пишите код, который нужно дополнять, а не переписывать".
Тут есть множество нюансов, но юнити - хороший пример, который предполагает, что вы будете писать свои компоненты, которые могут легко взаимодействовать со встроенными. Если вам нужно окно - ваше окно может использовать кнопки, тексты и картинки из стандартных компонентов.
Если нужно будет сделать другое - можно выкинуть код этого компонента и написать новый - виджеты не пострадают.
Liscov Substitution Principle - тут довольно просто, все дети должны вести себя как минимум как родители.
Основная причина - те, кто используют список базовых классов должны получать базовое же поведение, иначе старый и протестированный код можно поломать, написав новые классы (что очень тупо - ошибка то в новых классах, почему страдать должны старые?)
Если базовый класс поддерживает операции "нарисуй себя" и "обработай нажатие", то все наследники должны это делать, пусть и по своему. Как минимум они не должны падать с ошибкой или делать кульбиты при отрисовке. Если они реализуют пустую функцию-заглушку - это тоже может быть признаком плохого кода (хотя тут могут быть нюансы)
Unity использует это регулярно - у него есть большая иерархия компонентов и пользователь может наследоваться от многих из них и получать стандартное поведение компонентов.
Важно отметить, что зачастую не используется прямое наследование (Например Unity находит и вызывает метод Update как то хитро и скрыто).
Тем не менее Unity написала тысячи, а пользователи - сотни тысяч и миллионов компонентов, которые ведут себя как компоненты. Что позволяет вам их легко дополнять и даже переиспользовать чужие.
Interface Segregation Principle - тут все просто, интерфейсы должны быть маленькими и специализированными.
Основная причина - меньше неиспользуемого кода, более понятные компоненты.
Unity использует это даже без интерфейсов со своими основными методами - Update(), OnEnable(), OnDisable(), OnCollisionEnter(collider)
Другой пример - интерфейсы для UI
- IPointerClickHandler
- IPointerDownHandler
- IPointerEnterHandler
- IPointerExitHandler
- IPointerUpHandler
Как видно они связаны и, например, для реализации drag and drop нужно унаследовать несколько. Тем не менее для простых компонентов можно унаследовать лишь один и избежать пустого кода.
Dependency Inversion Principle - это пожалуй самый важный принцип для организации высокоуровневых связей.
Если писать код напрямую, то можно получить очень связанную лапшу - ведь кнопка вызывает игру, игра загружает сцену, сцена загружает солдатика а тот загружает пули.
Если каждый компонент из списка будет знать друг о друге, то во первых будет месиво, во вторых - код будет хрупким. Удали что-то из списка (например солдатика) и у тебя поломаются сразу сцена и пули.
Чтобы этого избежать, прямые зависимости нужно ограничивать только необходимыми местами, а связи осуществлять через абстракции.
Примеры из Unity
- OnCollisionEnter - вам не нужно знать про коллайдер физики и его тип. А коллайдеру физики не нужно знать про ваш компонент (и все возможные пользовательские компоненты). Вы оба знаете только про абстракцию - интерфейс (в данном случае это метод и Unity использует хак, но принцип тот же). Таким образом любая реализация физики может вызвать столкновение (просто вызвать OnCollisionEnter на всех компонентах, какими бы они ни были). Вы даже можете сделать свой тип коллайдера.
А любой логический компонент может быть потребителем события столкновения. Ему не нужно знать про существующие типы коллайдеров и с каким коллайдером мы работаем сейчас.
Получается компоненты можно расширять в 2 -х направлениях совершенно не беспокоясь о том, как они будут дружить, и все они не будут знать друг о друге ничего, потому что не нужно.
Другой пример абстракций - это свойства базового компонента. Unity знает, что компонент может быть включен и выключен (enable)
И если он включен - нужно вызывать Update().
Движок не интересует, что это за компонент и как он работает.
Именно за счет этого Unity так мощна а пользователи могут легко делать и переиспользовать компоненты.
Больше статей про солид в юнити! Новички должны страдать!
а как нарисовать в Юнити на gpu-карточке точку или линию ?) цветную без текстуры например, разного размера
и в 3д камерой обойти точку/линию вокруг )
SOLID для начинающих Unity-разработчиков: простыми словами и с примерами из жизни