2013-06-21 9 views
5

To proste pytanie. Widziałem wiele przypadków, w których kod jest realizowane tak:OOP - korzystanie z prywatnych nieruchomości i publicznego gettera

class User 
{ 
    private $id; 
    private $firstname; 
    private $lastname; 

    public function __construct() { some code } 

    public function getId() { return $this->id; } 

    public function getFirstname() { return $this->firstname; } 

    public function setFirstname($value) { $this->firstname = $value; } 
} 

// And properties are accessed like: 
$user->getFirstname(); 
$user->getId(); 

Więc co jest powodem korzystania z własności prywatnej i posiadające pobierające publicznych, zamiast tworzenia własności publicznej i dostęp do nich bezpośrednio, takich jak:

$user->firstname; 

PS: Czy jest OK, jeśli używam drugiej metody?

EDIT

Wydaje się, że nie dobrze badań przed tym pytaniem (chyba źle używane klawisze, aby szukać na ten temat). Oto kolejna dobra odpowiedź na (prawie) to samo pytanie: https://stackoverflow.com/a/1568230/1075534

Zasadniczo, za moim przypadku jeden dobry powód, aby korzystać z pobierające i ustawiające ma unikać zmieniania 250 klas, które bezpośrednio dostępu do właściwości. Tak na przykład, wyobraźmy sobie, że nie był przy użyciu getter:

class User 
{ 
    public $firstname = 'abc'; 
    public $lastname = 'cde'; 
} 

$user = new User(); 

echo $user->firstname . ' ' . $user->lastname; 

Teraz wyobraź sobie, że chcę zmienić zachowanie mojej aplikacji i zdecyduję się drukować nazwiska jak kapitalizowane. W takim przypadku przeszukałbym każdą implementację (w tym przypadku 250) i zamieniłabym dane wyjściowe w miejscu, w którym nazwałem właściwości. Ale raczej Gdybym użył getter to bym po prostu zmienić metodę getter:

class User 
{ 
    private $firstname = 'abc'; 
    private $lastname = 'def'; 

    public getFirstname() 
    { 
     return ucfirst(strtolower($this->firstname)); 
    } 

    public getLastname() 
    { 
     return ucfirst(strtolower($this->lastname)); 
    } 
} 

także pamiętać, że getter może gromadzić nie tylko informacje z jednego domu. Wyobraźmy sobie, co następuje:

class User 
{ 
    private $firstname = 'abc'; 
    private $lastname = 'def'; 

    public function getName() 
    { 
     return $this->firstname . ' ' . $this->lastname; 
    } 
} 

dla tych, którzy nadal masz pytania na ten temat, proponuję im czytanie materiałów, które dostarczone a zwłaszcza Gordon odpowiedź, że mam powiązany.

+0

Należy odczytać kod Kompletna 2. Ma doskonałe wyjaśnienie na ten temat i inne koncepcje rozwoju oprogramowania. – Gohn67

Odpowiedz

9

Korzystanie z akcesorów jest zgodne z Uniform Access Principle.

Cytując Wikipedię:

Uniform Dostęp Zasada była przedstawianej przez Bertranda Meyera. Stwierdza on: "Wszystkie usługi oferowane przez moduł powinny być dostępne za pośrednictwem jednolitej notacji, która nie zdradza, czy są one realizowane poprzez przechowywanie lub obliczenia." Ta zasada odnosi się ogólnie do języków programowania obiektowego. W prostszej formie stwierdza, że ​​nie powinno być żadnej różnicy między pracą z atrybutem, prekomputowaną właściwością lub metodą/zapytaniem.

W swoim blogu, Fowler explains

Skutecznie oznacza, że ​​klient osoby nie powinny wiedzieć ani obchodzi czy wiek jest przechowywany lub obliczone. Daje to podmiotowi możliwość elastycznego przełączania się między nimi, a także usuwania niepotrzebnego problemu ze strony klienta. To ważna część enkapsulacji - lub przynajmniej ukrywający aspekt enkapsulacji.

Aby zilustrować punkt, wyobraź sobie klasę tak:

class Now 
{ 
    public $timestamp; 

    public function getTomorrow() 
    { 
     return strtotime('+1 day', $this->timestamp); 
    } 

// … more code 

Kiedy robisz to w ten sposób, to zmusza programistę przy użyciu tej klasy poznać szczegóły implementacji. Aby uzyskać teraz jest znacznik czasu, deweloper ma do czynienia

echo $now->timestamp; 

natomiast aby uzyskać obliczony znacznik na jutro, deweloper ma do czynienia

echo $now->getTomorrow(); 

Ale deweloper nie powinien potrzebować opieki, więc jeśli chcesz podążać za UAP, dostarczysz Accessora, aby uzyskać znacznik czasu. I przenieś cały dostęp za pomocą metod.

Takie postępowanie ma także dodatkową zaletę, że jest bardziej stabilny. Wyobraź sobie, że musisz zmienić szczegóły implementacji później w projekcie i przekształcić znacznik czasu w obiekt DateTime. Klasa teraz wygląda tak:

class Now 
{ 
    public $dateTime; // <-- no longer just a timestamp 

    public function getTomorrow() 
    { 
     return strtotime('+1 day', $this->dateTime->getTimestamp()); 
    } 

// … more code 

Teraz każdy deweloper, który poprzednio używane $now->timestamp będzie musiał zmienić swój kod czasochłonne, aby pomieścić do tej zmiany. Podczas gdy używałeś Gettera od samego początku, nie stanowiłoby to żadnego problemu, ponieważ Getter upewniłby się, że zwróci znacznik czasu. Aby jeszcze bardziej udowodnić tę kwestię, zwróć uwagę, że deweloper nie musiałby niczego zmieniać, aby konsumować getTomorrow(). Chociaż wewnętrznie zmieniliśmy szczegóły, publiczny interfejs API nadal zachowuje się tak samo.

Należy pamiętać, że UAP jest tylko wytyczną. Nowoczesne IDE sprawiają, że łatwe jest generowanie Akcesoriów i Mutatorów, więc łatwo jest je śledzić. Ale to nie jest absolutna prawda. Jeśli możesz rozsądnie uzasadnić, że go nie przestrzegasz, nie stosuj się do niego i używaj właściwości publicznych. Ale powinna to być świadoma decyzja.

Jednak ogólnie rzecz biorąc, you want to avoid Getters (i setery) tak czy inaczej i just tell your objects what to do. Da to znacznie szczuplejsze API. Jeśli Twój interfejs API zawiera dużo funkcji Getters, istnieje możliwość rozpraszania kodu, który naprawdę powinien znajdować się wewnątrz obiektu w obrębie konsumentów.

+1

To naprawdę dobra odpowiedź. Dzięki za udostępnienie! –

+0

Dzięki @Gordon, naprawdę świetna odpowiedź. Czytałem cały materiał, który dostarczyłeś. Ale wciąż mam pytanie. Zasadniczo zadałem to pytanie klasie użytkownika, którą zamierzałem napisać. Ponieważ może mieć wiele właściwości (takich jak imię, nazwisko, adres e-mail, hash, utworzone itp ...) i biorąc pod uwagę, że zdecyduję się przestrzegać zasady UAP, zakończę wiele partii pobierających i ustawiających. Uważam, że w tym przypadku nie ma nic złego, jeśli unikam zdobywców i seterów, prawda? –

+0

@SavasVedova Jeśli klasa jest tylko strukturą danych, to * może *. Sugeruję jednak, aby nie pytać, czy powinieneś go przestrzegać, ale raczej pytanie, dlaczego nie podążałbyś za nim w przyszłości, by potwierdzić twój kod i tak łatwo jest wygenerować je automatycznie. – Gordon

2

Gdy zmienna jest zadeklarowana jako publiczna, jest dostępna z dowolnej klasy, co ułatwia pracę programisty; w ten sposób wyjaśniając twoje pragnienie użycia drugiej opisanej metody. Jednak niektóre zmienne muszą być zadeklarowane jako prywatne ze względów bezpieczeństwa (czasami jest to postrzegane jako dobra praktyka). Fakt, że deklarujemy je jako prywatne, jest dostępny tylko w ich własnej klasie. Jeśli jednak musisz ich użyć w funkcji innej klasy, musisz zastosować pierwszą metodę opisaną przez ciebie.

2

użycie gettera powoduje, że jest on tylko do odczytu.

(to jedyna różnica koncepcyjne. Język można łatwo pozwalają interfejsy być definiowane w kategoriach własności, jak również metod. Konwencje nazewnictwa nie są naprawdę podstawowe.)

Powiązane problemy