Рассмотрим два класса Dog
и Cat
как в соответствии с Animal
протоколом (с точки зрения языка программирования Swift. Это было бы интерфейс в Java / C #).
У нас есть экран со смешанным списком собак и кошек. Есть Interactor
класс, который обрабатывает логику за кулисами.
Теперь мы хотим предоставить пользователю подтверждение, когда он хочет удалить кошку. Тем не менее, собаки должны быть удалены немедленно без каких-либо предупреждений. Метод с условиями будет выглядеть так:
func tryToDeleteModel(model: Animal) {
if let model = model as? Cat {
tellSceneToShowConfirmationAlert()
} else if let model = model as? Dog {
deleteModel(model: model)
}
}
Как этот код может быть реорганизован? Это явно пахнет
источник
Dog
иCat
описываются как классы, в то времяAnimal
как это протокол, который реализуется каждым из этих классов. Так что между вопросом и вашим ответом есть небольшое несоответствие.Interactor
теперь зависит от состоянияCat
иDog
обрабатываются, оно может и должно быть общим свойствомAnimal
. Чтобы сделать что-то еще, нужно просить головную боль за обслуживание позже.Скажи против спроси
Условный подход, который вы демонстрируете, мы бы назвали « спросить ». Вот где потребитель-клиент спрашивает: «Какой ты?» и настраивает их поведение и взаимодействие с объектами соответственно.
Это контрастирует с альтернативой, которую мы называем « сказать ». Используя Tell , вы вкладываете большую часть работы в полиморфные реализации, так что потребляющий клиентский код проще, без условных выражений и является общим независимо от возможных реализаций.
Поскольку вы хотите использовать подтверждающее предупреждение, вы можете сделать это явной возможностью интерфейса. Таким образом, у вас может быть логический метод, который опционально проверяет пользователя и возвращает логическое подтверждение. В тех классах, которые не хотят подтверждать, они просто переопределяются
return true;
. Другие реализации могут динамически определять, хотят ли они использовать подтверждение.Потребляющий клиент всегда будет использовать метод подтверждения независимо от того, с каким конкретным подклассом он работает, что заставляет взаимодействие сообщать, а не спрашивать .
(Другой подход заключается в том, чтобы подтолкнуть подтверждение к удалению, но это удивит потребителей, которые ожидают, что операция удаления будет успешной.)
источник
Interactor
теперь зависит от состоянияОтветственность за определение необходимости подтверждения лежит на
Cat
классе, поэтому дайте ему возможность выполнить это действие. Я не знаю Kotlin, поэтому я буду выражать вещи в C #. Надеемся, что тогда идеи будут переданы и Котлину.Затем при создании
Cat
экземпляра вы предоставляете егоTellSceneToShowConfirmationAlert
, который нужно будет вернуть,true
если OK для удаления:И тогда ваша функция становится:
источник
Cat
классе. Я бы сказал, что это то, где оно принадлежит. Он не может решить, как это подтверждение получено (то есть введено), и он не удаляет себя. Так что нет, это не перемещает логику удаления в модель.TellSceneToShowConfirmationAlert
в случайCat
. В ситуациях, когда это нелегко (например, в многослойной системе, где эта функциональность находится на глубоком уровне), такой подход не будет хорошим.Я бы посоветовал пойти на шаблон посетителя. Я сделал небольшую реализацию в Java. Я не знаком со Swift, но вы можете легко адаптировать его.
Посетитель
Ваша модель
Звонить посетителю
Вы можете иметь столько реализаций AnimalVisitor, сколько захотите.
Пример:
источник