Aby zdefiniować metodę dla klasy, musimy użyć funkcji UseMethod(), aby zdefiniować hierarchię funkcji. Poinstruuje R, aby szukał funkcji, której prefiks pasuje do bieżącej funkcji i sufiksu w kolejności od wektora nazw klas przekazywanego obiektu. Nazwy metod mają dwie części oddzielone znakiem „”, gdzie przedrostek to nazwa funkcji, a przyrostek to nazwa klasy. Jak widać, funkcje ogólne S3 działają na podstawie konwencji nazewnictwa, a nie jawnej rejestracji metod dla różnych klas. Zaczynamy od stworzenia metody S3area dla klasy S3Rectangle, a robimy to tworząc funkcję o nazwie S3area.S3Rectangle. Funkcja UseMethod() upewni się, że funkcja S3area.S3Rectangle otrzyma obiekt klasy S4rectangle, więc wewnątrz takiej funkcji możemy skorzystać z elementów wewnętrznych klasy. W tym przypadku weźmiemy długości a i b i pomnożymy je razem:
S3area.S3Rectangle <- function(rectangle) {
return(rectnagle$a * rectnagle$b)
}
Zauważ, że możemy uzyskać dostęp do takich obiektów w obiekcie rectangle za pomocą operatora $. Nie jest to ograniczone do wykonania w ramach metody, więc tak naprawdę każdy obiekt może zmienić elementy wewnętrzne obiektu S3, ale tylko dlatego, że możesz, nie oznacza, że powinieneś.
Teraz wywołamy metodę S3area ,t ak, jakby to było normalne wywołanie funkcji, do którego przekażemy utworzony wcześniej prostokąt prostokątny i powinniśmy zobaczyć, jak obszar jest drukowany do konsoli:
S23area(s3_rectangle)
#> Błąd w S3area (S3_rectangle): nie można znaleźć funkcji „S3area”
Co się stało? Błąd? W jaki sposób R może stwierdzić, że wywołanie funkcji S3area powinno faktycznie wyzwolić wywołanie metody S3area.S3Rectangle? Aby tak się stało, musimy zarejestrować nazwę za pomocą R i robimy to, wywołując funkcję definiującą, która w rzeczywistości sama używa nazwy S3area. Ta funkcja S3area otrzymuje obiekt dowolnego typu, niekoniecznie a, i używa funkcji to, aby powiedzieć, że powinna poszukaj wywołania metody „S3area”dla tego obiektu. W tym przypadku wiemy, że zostanie znaleziony tylko dla klasy S3Rectangle:
S3area <- functin(object) {
USeMethod(„S3area”)
}
Teraz możemy wywołać metodę S3area tak jak poprzednio, ale w tym przypadku uzyskamy rzeczywisty obszar. Oto jak zwykle tworzysz metody za pomocą S3:
S3area(S3_rectangle)
#> [1] 6
Teraz utworzymy metodę S3Color, aby zwrócić obiekt koloru dla prostokąta. Ponieważ obiekt koloru jest tylko typem znaków, nie musimy nic więcej zrobić, aby jakoś przeanalizować ten obiekt, jeśli chcemy tylko znaków:
S3color.S3Rectnagle <- function(rectangle) {
return(rectnagle$color)
}
S3color <- function(object) {
UseMethod(„S3color”)
}
Teraz wyświetlamy prostokąt. Jak widać, wywołanie print()po prostu pokazuje nam wnętrze obiektu i obiektów w nim zawartych:
print(S3_rectangle)
#> $ a
#> [1] 2
#>
#> $ b
#> [1] 3
#>
#> $ kolor
#> [1] “niebieski”
#> attr (, “klasa”)
#> [1] “S3Color”
#>
#> attr (, “klasa”)
#> [1] “S3Rectangle”
Możemy chcieć przeciążać tę funkcję, aby zapewnić inne wyjście. Aby to zrobić, tworzymy print.S3Rectnagle() i po prostu wyświetlamy ciąg, który powie nam kolor prostokąta, fakt, że jest to prostokąt, długość każdy z jego boków, a następnie jego obszar. Zauważ , że zarówno kolor, jak i obszar są pobierane przy użyciu metod, które zdefiniowaliśmy wcześniej, S3Color i S3areAa():
print.S3Rectnagle <- function(rectnagle) {
print(paste(
S3olor(rectangle), „rectangle:”,
rectnagle$a, „x”, rectangle$b , „==”, S3area(rectangle)
))
}
A teraz, co powinno się stać, gdybyśmy po prostu wywołali funkcję print(), tak jak wcześniej z funkcją S3area()? Powinniśmy otrzymać błąd, prawda? Spójrzmy na następujący kod:
print(S3_rectangle)
#> [1] “niebieski prostokąt: 2 x 3 == 6”
Jak widać, nie mamy. W tym przypadku otrzymamy wynik, na który mieliśmy nadzieję. Powodem jest to, że funkcja print() w R jest funkcją S3, która została już zarejestrowana z funkcją UseMethod(). Oznacza to, że nasza definicja print.S3Rectangle nie musi być ponownie rejestrowana i możemy po prostu jej użyć. To całkiem fajne, prawda? To jedna z największych zalet stosowania polimorfizmu parametrycznego. Możemy rejestrować funkcje jako wywołania metod, których możemy, ale nie muszą, używać w przyszłości w nieoczekiwany sposób, ale nadal zapewniają one jednorodny interfejs dla użytkownika.