Jak użycie wzorca Singleton może naruszać zasady polimorfizmu?
sobes.tech AI
Odpowiedź od AI
Singleton ogranicza tworzenie instancji klasy do jednego obiektu. Polimorfizm natomiast zakłada możliwość pracy z obiektami różnych klas przez wspólny interfejs lub klasę bazową.
Naruszenie występuje, gdy kod klienta jest sztywno powiązany z konkretną klasą Singleton, zamiast pracować z abstrakcją (protokołem lub klasą bazową). W takim przypadku nie można podmienić innego, alternatywnego obiektu, który implementuje tę samą funkcjonalność, ponieważ klient oczekuje dokładnie instancji Singleton.
// Złe użycie - klient bezpośrednio zależy od ConcreteSingleton
class ConcreteSingleton {
static let shared = ConcreteSingleton()
private init() {}
func performAction() {
print("Wykonywanie akcji z ConcreteSingleton")
}
}
// Klient
func clientFunction() {
// Sztywne powiązanie z ConcreteSingleton
ConcreteSingleton.shared.performAction()
}
// Dobre użycie - klient zależy od protokołu
protocol Service {
func performAction()
}
class RealService: Service {
func performAction() {
print("Wykonywanie akcji z RealService")
}
}
class MockService: Service {
func performAction() {
print("Wykonywanie akcji z MockService")
}
}
// Singleton do dostarczania implementacji przez protokół (opcjonalnie, można użyć DI)
class ServiceProvider {
static let shared = ServiceProvider()
private init() {}
private var currentService: Service = RealService()
func setService(_ service: Service) {
currentService = service
}
func getService() -> Service {
return currentService
}
}
// Klient
func flexibleClientFunction() {
// Praca przez abstrakcję (protokół)
let service = ServiceProvider.shared.getService()
service.performAction()
}
// Przykłady polimorfizmu z elastycznym klientem
// ServiceProvider.shared.setService(MockService())
// flexibleClientFunction() będzie używać MockService
W ten sposób, bezpośrednie korzystanie z właściwości statycznej shared Singletona w kodzie klienta obniża elastyczność i utrudnia podmianę implementacji, co jest kluczowym aspektem polimorfizmu przy pracy z różnymi typami obiektów przez wspólny interfejs. Rozwiązaniem jest korzystanie z instancji Singletona przez protokół lub klasę bazową.