při vytváření softwaru je užitečné pochopit širokou škálu principů návrhu. Pochopení toho, jak navrhnout systém s nejvhodnějším principem, může ušetřit nespočet hodin vývoje a bolesti hlavy.

Pojďme si nejprve trochu promluvit o dědičnosti. Dědičnost je, když třída zdědí stav a / nebo chování od nadřazené třídy. Řekněme, že navrhujeme hru a potřebuji psa:

class Dog {
func bark(){
print("Bark")
}
}

po chvíli si uvědomíme, že náš software, stejně jako všechno, potřebuje kočky, takže vytváříme třídu koček:

class Cat{
func .meow(){
print("Meow!")
}
}

protože příroda volá, přidáme .hovínko () do třídy koček a psů:

class Dog {
func bark(){
print("Bark")
}
func poop(){
print("Poop")
}
}class cat{
func meow(){
print("Meow")
}
func poop(){
print("Poop")
}
}

v tomto příkladu máme dvě zvířata, která jsou schopna hovno. Bohužel, oba poskytují implementace pro poop(), takže je zde nějaká duplikace kódu. tak se zvedáme .hovínka () do společné třídy zvířat.

Animal
.poop()Dog
.bark()Cat
.meow()

Nyní, když máme všude spoustu zvířat, potřebujeme úklidrobot:

CleaningRobot
.drive()
.clean()

také potřebujete MurderRobot, který může .řídit () a .zabít() kočky a psy, které jsou .poop () ing po celé své bílé podlahy:

MurderRobot
.drive()
.kill()

od té doby .drive () je nyní duplikován mezi CleaningRobot a MurderRobot vytvoříme třídu robotů, do které ji vložíme.

Robot
.drive()CleaningRobot
.clean()MurderRobot
.kill()

takto vypadá celá struktura:

Robot
.drive()CleaningRobot
.clean()MurderRobot
.kill()Animal
.poop()Dog
.bark()Cat
.meow()

„naši zákazníci požadují MurderRobotDog. Musí být schopen .zabít(), .disco(), .kůra (), ale nemůže hovno ().

a teď jsme v háji. Do této hierarchie dědictví prostě nemůžeme vhodit Murderrobotdoga pěkně. Mohli bychom vytvořit nový nadřazený objekt, kam vložíte všechny sdílené funkce:

GameObject
.bark()Robot
.drive()CleaningRobot
.clean()MurderRobot
.kill()MurderRobotDogAnimal
.poop()DogCat
.meow()

ale to znamená, že vaše objekty budou mít spoustu funkcí, které nepoužívají, takže skončíte s problémem gorily/banánů — požádáte o banán, ale skončíte s gorilou, která drží banán a celou džungli s ním.

to však můžeme modelovat pomocí protokolů ve Swiftu.Jak mohou protokoly poskytnout lepší abstrakci?

protokol ve Swiftu definuje metody nebo vlastnosti, které pak třída může přijmout. Zde je příklad:

protocol Barker {
func bark()
}
protocol Pooper {
func poop()
}
protocol Driver {
func drive()
}
protocol Cleaner {
func clean()
}
protocol Killer {
func kill()
}

protože třídy mohou přijmout více protokolů. Třída MurderRobotDog přijímá protokol Barker, Killer and driver, což znamená, že třída MurderRobotDog poskytuje implementace pro bark(), kill(), and clean().

class MurderRobotDog: Barker,Killer, Driver{
func bark() {
print("Bark!")
}
func driver() {
print("Drive!")
}
func killer() {
print("Kill!")
}}

od Swift 2.0 můžeme nyní odstranit duplikaci kódu poskytnutím výchozí implementace pomocí rozšíření protokolu:

protocol Barker {
func bark()
}
extension Barker {
func bark() {
print("Bark!")
}
}class Dog: Barker{}
let myDog = Dog()
myDog.bark() // prints "Bark!"

podívali jsme se na příklad stromu dědičnosti, který se rozpadl, a pak jsme se podívali na to, jak jej restrukturalizovat pomocí protokolu (rozhraní).

otázka, která je pravděpodobně na vaší mysli nyní je-kdy použít každý z nich? No … drtivá většina vývojářů souhlasí s tím, že bychom měli upřednostňovat rozhraní před dědičností. Mnoho lidí vám řekne, že pokud má něco vztah“ je“, měli byste použít dědictví. Například Mattias “ je “ muž, a tak mohu zdědit člověka. Pokud je vztah“ má „povahu, například auto“ má “ motor, pak byste měli použít složení.

závěr

při navrhování systému je důležité zvolit správný princip návrhu pro váš model. V mnoha případech je lepší použít rozhraní na prvním místě. Je to flexibilnější, výkonnější a je to také velmi snadné.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.