Мне нужно создать новый класс.Некоторые его функции уже находятся в другом классе, и с точки зрения домена имеет смысл наследовать от него.Проблема в том, что существует метод, который должен быть более ограниченным по своему типу параметра, потому что из-за LSP (принцип подстановки Лискова) вы не можете перезаписать его.
До сих пор существует код, который я могу изменить,
Для лучшего объяснения приведу простой пример:
У меня есть AnimalShelter
, и мне нужно реализовать DogShelter
.
class AnimalShelter {
func usefulMethod(...) {}
func take(x: Animal) {}
}
class DogShelter {
var dogMedianCuteness: String = "normal (= very cute)"
func usefulMethod(...) {}
func take(x: Dog) {}
}
Решение 1: Подкласс
Если DogShelter
является подклассом AnimalShelter
, он получит usefulMethod(...)
бесплатно, но унаследованный метод take(x: Animal)
не может быть переопределен и загрязняет API DogShelter и должен просто ничего не делать иливыдает ошибку.
class AnimalShelter {
func usefulMethod(...) {}
func take(x: Animal) {}
}
class DogShelter: AnimalShelter {
var dogMedianCuteness: String = "normal (= very cute)"
func take(x: Dog) {}
}
Решение 2. Протокол + расширение протокола
Если AnimalShelter
и DogShelter
реализуют протокол, он не является точным с точки зрения домена, но является общимкод usefulMethod(...)
может быть реализован в протоколе extension
.
protocol UsefulThing {
func usefulMethod(...)
}
extension UsefulThing {
func usefulMethod(...) { ... }
}
class AnimalShelter: UsefulThing {
func take(x: Animal) {}
}
class DogShelter: UsefulThing {
var dogMedianCuteness: String = "normal (= very cute)"
func take(x: Dog) {}
}
Решение 3. Обобщение, создать еще один суперкласс
Проблема в take(x: T)
метод, который более специализирован в DogShelter
.Извлечение его из AnimalShelter позволит без проблем наследовать, но все, что до сих пор использовало AnimalShelter, должно быть заменено новым подклассом AnyAnimalShelter: AnimalShelter
с проблемным take(x: Animal) {}
class AnimalShelter {
usefulMethod(...) {}
}
class AnyAnimalShelter: AnimalShelter {
take(x: Animal) {}
}
class DogShelter: AnimalShelter {
var dogMedianCuteness: String = "normal (= very cute)"
func take(x: Dog) {}
}
Решение 4: Состав
Наследование имеет смысл с точки зрения домена, поэтому босс считает, что лучше всего его сохранить.
Итак, я получил код от AnimalShelter
и мне разрешено его менять, хотяэто вызовет удивление, почему я бы поменял код, который отлично работает годами.Мне нужна абстрактная причина о том, что метод take(x: Animal)
имеет недостатки в AnimalShelter
.Не только иметь веские аргументы против этого, но и избегать этого в будущих классах.
Было бы настоящей проблемой, если бы я не мог изменить код, который использует AnimalShelter
или AnimalShelter
сам.
Вопрос
Как кто-то / я должен смоделировать это?