Задача состоит в том, чтобы настроить аппаратную часть устройства, в соответствии с некоторой входной спецификацией. Это должно быть достигнуто следующим образом:
1) Соберите информацию о конфигурации. Это может случиться в разное время и в разных местах. Например, модуль A и модуль B могут одновременно запрашивать (в разное время) некоторые ресурсы из моего модуля. Эти «ресурсы» на самом деле представляют собой конфигурацию.
2) После того, как станет ясно, что запросы больше не будут реализованы, на аппаратное обеспечение необходимо отправить команду запуска, дающую сводку запрошенных ресурсов.
3) Только после этого можно (и нужно) проводить детальную настройку указанных ресурсов.
4) Кроме того, только после 2) может (и должна) быть выполнена маршрутизация выбранных ресурсов объявленным абонентам.
Общая причина ошибок, даже для меня, который написал вещь, принимает этот заказ. Какие соглашения об именах, проекты или механизмы я могу использовать, чтобы сделать интерфейс пригодным для использования тем, кто впервые видит код?
источник
discovery
илиhandshake
?Ответы:
Это редизайн, но вы можете предотвратить неправильное использование многих API, но не имея доступных методов, которые не должны вызываться.
Например, вместо
first you init, then you start, then you stop
Ваш конструктор
init
является объектом, который может быть запущен, иstart
создает сеанс, который можно остановить.Конечно, если у вас есть ограничение на один сеанс за раз, вам нужно разобраться со случаем, когда кто-то пытается создать сеанс с одним уже активным.
Теперь примените эту технику к вашему собственному делу.
источник
zlib
иjpeglib
два примера, которые следуют этому шаблону для инициализации. Тем не менее, множество документов необходимо, чтобы научить разработчиков концепции.Вы можете заставить метод запуска возвращать объект, который является обязательным параметром для конфигурации:
Даже если ваша структура
MySession
просто пустая, благодаря безопасности типов это обеспечит невозможностьConfigure()
вызова метода перед запуском.источник
module->GetResource()->Configure(nullptr)
?a, b, c, d
, я могу начатьa
и использовать их,MySession
чтобы попытаться использоватьb
в качестве уже запущенного объекта, тогда как в действительности это не так.Основываясь на ответе Cashcow - зачем вам представлять вызывающему объект новый объект, когда вы можете просто представить новый интерфейс? Rebrand-шаблон:
Вы также можете позволить ITerminateable реализовать IRunnable, если сеанс может быть запущен несколько раз.
Ваш объект:
Таким образом, вы можете вызывать только правильные методы, так как у вас есть только IStartable-Interface в начале и вы получите метод run (), доступный только тогда, когда вы вызвали start (); Со стороны это выглядит как шаблон с несколькими классами и объектами, но базовый класс остается одним классом, на который всегда ссылаются.
источник
Существует много подходящих подходов для решения вашей проблемы. Бэзил Старынкевич предложил подход «нулевой бюрократии», который оставляет вам простой интерфейс и полагается на программиста, использующего соответствующий интерфейс. Несмотря на то, что мне нравится этот подход, я представлю другой, который имеет больше возможностей, но позволяет компилятору отлавливать некоторые ошибки.
Определение различных состояний устройство может быть, так как
Uninitialised
,Started
,Configured
и так далее. Список должен быть конечным.Для каждого состояния определите наличие
struct
необходимой дополнительной информации, относящейся к этому состоянию, напримерDeviceUninitialised
,DeviceStarted
и так далее.Упакуйте все обработки в один объект,
DeviceStrategy
где методы используют структуры, определенные в 2. как входы и выходы. Таким образом, у вас может бытьDeviceStarted DeviceStrategy::start (DeviceUninitalised dev)
метод (или любой другой эквивалент в соответствии с соглашениями вашего проекта).При таком подходе действительная программа должна вызывать некоторые методы в последовательности, реализуемой прототипами методов.
Различные состояния являются несвязанными объектами, это происходит из-за принципа замещения. Если вам полезно, чтобы эти структуры имели общего предка, помните, что шаблон посетителя можно использовать для восстановления конкретного типа экземпляра абстрактного класса.
Хотя я описал в 3. уникальном
DeviceStrategy
классе, есть ситуации, когда вы можете разделить функциональность, которую он предоставляет, на несколько классов.Чтобы суммировать их, ключевые моменты дизайна, который я описал:
Из-за принципа подстановки объекты, представляющие состояния устройства, должны различаться и не иметь особых отношений наследования.
Упакуйте обработки устройств в объекты стратегии, а не в объекты, представляющие сами устройства, чтобы каждое устройство или состояние устройства видело только себя, а стратегия видит все из них и выражала возможные переходы между ними.
Клянусь, я однажды увидел описание реализации клиента telnet, следующее за этими строками, но я не смог найти его снова. Это была бы очень полезная ссылка!
For: Для этого либо следуйте своей интуиции, либо найдите классы эквивалентности методов в вашей фактической реализации для отношения «метод₁ ~ метод₂». допустимо использовать их на одном и том же объекте »- при условии, что у вас есть большой объект, инкапсулирующий все процедуры на вашем устройстве. Оба метода перечисления состояний дают фантастические результаты.
источник
Используйте шаблон строителя.
Имейте объект, у которого есть методы для всех операций, которые вы упомянули выше. Тем не менее, он не выполняет эти операции сразу. Он просто запоминает каждую операцию на потом. Поскольку операции выполняются не сразу, порядок их передачи строителю не имеет значения.
После того, как вы определили все операции с компоновщиком, вы вызываете
execute
-method. Когда вызывается этот метод, он выполняет все шаги, перечисленные выше, в правильном порядке с операциями, которые вы сохранили выше. Этот метод также является хорошим местом для выполнения некоторых проверок работоспособности (например, попытка настроить ресурс, который еще не был настроен) перед записью их на аппаратное обеспечение. Это может уберечь вас от повреждения оборудования с бессмысленной конфигурацией (в случае, если ваше оборудование подвержено этому).источник
Вам просто нужно правильно документировать, как используется интерфейс, и привести учебный пример.
У вас также может быть вариант библиотеки отладки, который выполняет некоторые проверки во время выполнения.
Возможно определение и правильно документировать некоторые соглашения об именах (например
preconfigure*
,startup*
,postconfigure*
,run*
....)Кстати, многие существующие интерфейсы следуют подобному шаблону (например, наборы инструментов X11).
источник
Это действительно распространенная и коварная ошибка, потому что компиляторы могут применять только синтаксические условия, а клиентские программы должны быть «грамматически» правильными.
К сожалению, соглашения об именах практически неэффективны против такого рода ошибок. Если вы действительно хотите, чтобы люди не делали неграмотных вещей, вы должны раздать какой-либо командный объект, который должен быть инициализирован значениями предварительных условий, чтобы они не могли выполнять шаги не по порядку.
источник
Используя этот шаблон, вы уверены, что любой разработчик будет работать в этом точном порядке. Вы можете пойти еще дальше и создать ExecutorFactory, которая будет создавать исполнителей с пользовательскими путями выполнения.
источник
step1(); step2(); step3();
. Задача построителя шагов состоит в том, чтобы предоставить API, который предоставляет некоторые шаги, и обеспечить последовательность, в которой они вызываются. Это не должно мешать программисту делать другие вещи между шагами.