Teraz zobaczymy, jak S3 obsługuje zmienność i hermetyzację. Aby to zrobić, wydrukujemy wartość- w prostokącie, zmodyfikujemy ją i wydrukujemy ponownie. Jak widać, jesteśmy w stanie go zmodyfikować i od tego momentu otrzymujemy inny wynik i robimy to bez wywoływania metod. To bardzo ryzykowna rzecz i zdecydowanie powinieneś zawrzeć tego typu zachowanie w wywołaniach metod:
print(S3_rectangle$a)
#> [1] 2
S3_rectangle$a <- 1
print(S3_rectangle$a)
#> [1] 1
Nawet jeśli możesz, nigdy nie modyfikuj bezpośrednio elementów wewnętrznych obiektu.
Właściwym sposobem modyfikowania obiektu byłoby użycie jakiejś funkcji ustawiającej. Metoda set_color.S3Rectnagle zostanie użyta do zmodyfikowania koloru prostokąta, otrzymując S3Rectnagle i a string new_color i zapisanie tego nowego łańcucha wewnątrz atrybutu color w prostokącie. Kiedy używasz takiej metody, jasno wyrażasz swoje zamiary, co jest znacznie lepszym sposobem programowania. Oczywiście musimy również zarejestrować wywołanie metody za pomocą R, jak pokazano wcześniej:
set_color.S3Rectangle <- function(rectangle, new_color) {
rectangle$olor <- new_color
return(rectnagle)
}
set_color <- function(object, new_color) {
UseMethod(„set_color”)
}
Czy zauważyłeś nasz błąd? Prawdopodobnie nie, ale świetnie, gdybyś to zrobił! Zrobiliśmy to celowo, aby pokazać, jak łatwo jest wyrządzić sobie krzywdę programując w R. Ponieważ R nie ma funkcji sprawdzania typu, przypadkowo przypisaliśmy łańcuch, do którego powinniśmy przypisać Color. Oznacza to, że atrybut color w naszym prostokącie nie będzie już rozpoznawany jako klasa Color po wywołaniu metody set_color() zostanie rozpoznany jako ciąg. Jeśli twój kod zależy od tego, czy obiekt jest typu Color, prawdopodobnie zakończy się niepowodzeniem w nieoczekiwany i mylący sposób i będzie trudny do debugowania. Zachowaj ostrożność podczas wykonywania zadań. Zamiast tego powinniśmy umieścić rectangle$color <- color_constructor(new_color) aby zachować spójność. Chociaż możesz zmienić typ obiektu, nigdy nie powinieneś. Jak to ujął Hadley Wickham, R nie chroni cię przed sobą: możesz łatwo strzelić sobie w stopę. Dopóki nie wycelujesz pistoletu w stopę i nie pociągniesz za spust, nie będziesz miał problemu. Teraz pokażemy, jak można zastosować metodę set_color(). Wyświetlimy kolor prostokąta, spróbujemy zmienić go na czarny i wydrukujemy ponownie. Jak widać, zmiana nie została utrwalona w naszym obiekcie. Dzieje się tak, ponieważ R przekazuje obiekty przez wartość, a nie przez odniesienie. Oznacza to po prostu, że kiedy modyfikujemy prostokąt, tak naprawdę modyfikujemy kopię prostokąta, a nie prostokąta, który sami przekazaliśmy:
print(S3color(S3_rectangle))
#> [1] “blue”
#> attr (, class”)
#> [1] “S3Color”
set_color(S3_rectangle, „black”)
#> [1] “czarny prostokąt: 1 x 3 == 3”
print(S3color(S3_rectnagle))
#> [1] “blue”
#> attr (, “class”)
#> [1] “S3Color”
Czy zauważyłeś, że pod koniec funkcji set_color.S3Rectangle wróciliśmy do rectangle? W innych językach, które mogą nie być konieczne, ale w R robimy to, aby odzyskać zmodyfikowany obiekt. Aby utrzymać zmiany w naszym obiekcie, musimy faktycznie przypisać ten wynikowy obiekt do naszego własnegoS3_rectangle, a kiedy to zrobimy, możemy zobaczyć, że zmiana koloru została utrzymana. Ta właściwość nadaje S3 jego niezmienność. Jest to bardzo przydatne podczas pracy z programowaniem funkcjonalnym, ale może być nieco kłopotliwe podczas programowania zorientowanego obiektowo. Ta właściwość może powodować pewne mylące błędy, które przyzwyczają Cię do pracy w ten sposób