2013-06-21 87 views
5

只是一個簡單的問題。我見過許多情況下,代碼等實現的以下內容:OOP - 使用私有財產和公共獲取者

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(); 

那麼,什麼是使用私有屬性和公衆有干將,而不是使性能市民和直接訪問他們喜歡的原因:

$user->firstname; 

PS:如果我使用第二種方法,可以嗎?

編輯

好像我沒有問這個問題之前,研究以及(猜我用錯了鍵搜索的主題)。下面是幾乎同樣的問題的另一個很好的答案:https://stackoverflow.com/a/1568230/1075534

基本上,對我而言,使用getters和setter的一個很好的理由是避免更改直接訪問屬性的250個類。因此,舉例來說,假設我沒有使用一個getter:

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

$user = new User(); 

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

現在,假設我想改變我的應用程序的行爲,我決定爲資本進行打印的名稱。在這種情況下,我會搜索每個實現(在這種情況下爲250),並在任何稱爲屬性的位置大寫輸出。但是,而如果我用一個getter,那麼我會只是改變了getter方法:

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

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

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

另外,請記住,一個getter可能不僅是從一個單一的屬性收集信息。想象一下以下內容:

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

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

對於那些誰仍然對此事有疑問,我建議他們讀戈登提供的材料,特別是,我已經掛了答案。

+0

你應該閱讀代碼完成2。它有一個關於這個主題和其他軟件開發概念的很好的解釋。 – Gohn67

回答

9

使用訪問器滿足Uniform Access Principle

引述維基百科:

的統一訪問原則被伯特蘭·邁耶提出。它指出:「一個模塊提供的所有服務都應該通過一個統一的表示法來提供,而不會出賣它們是通過存儲還是通過計算來實現。」這個原則一般適用於面向對象的編程語言。以更簡單的形式表示,在使用屬性,預計算屬性或方法/查詢之間應該沒有區別。

在他的博客中,Fowler explains

這實際上就意味着這個人的客戶端應該不知道,也不關心年齡是否存儲或計算。這使得個人對象可以輕鬆地在兩者之間進行切換,也可以消除客戶通常不需要關心的問題。這是封裝的一個重要部分 - 或者至少是封裝的數據隱藏方面。

爲了說明這一點,試想一類是這樣的:

class Now 
{ 
    public $timestamp; 

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

// … more code 

當你做這種方式,您使用的類來了解實現的細節迫使開發商。爲了讓現在的時間戳,開發商必須做

echo $now->timestamp; 

而獲得明天的計算時間戳,開發商必須做

echo $now->getTomorrow(); 

但開發商不應該需要照顧,所以如果你想跟隨UAP,你將提供一個Accessor來獲得時間戳。通過方法漏斗所有訪問。

這樣做也具有更穩定的API的額外好處。想象一下,您需要在項目後面更改實施細節,並將時間戳記轉換爲DateTime對象。你的類現在看起來是這樣的:

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

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

// … more code 

現在,以前使用$now->timestamp將不得不改變他們的消費代碼,以適應該變化的任何開發。而當你從一開始就使用Getter時,它根本就不是問題,因爲Getter會確保它返回時間戳。爲了進一步證明這一點,請注意開發者如何不必改變任何東西來消費getTomorrow()。雖然內部我們改變了細節,但公共API仍然表現相同。

請注意,UAP只是一個指導原則。現代的IDE讓你很容易爲你生成Accessors和Mutators,所以很容易遵循。但這不是絕對的事實。如果你可以合理地證明不遵循它,那麼不要遵循它並使用公共財產。但它應該是一個明智的決定。

然而,一般而言,you want to avoid Getters(和Setters)無論如何和just tell your objects what to do。這將提供更簡單的API。如果你的API有很多Getter,那麼你很可能將代碼真正應用到對象中。

+1

這是一個非常好的答案。感謝分享! –

+0

謝謝@戈登,非常好的答案。我一直在閱讀你提供的所有材料。但我仍然有一個問題。我主要問這個問題,我想寫一個用戶類。因爲它可能有很多屬性(如名字,姓氏,電子郵件,哈希,創建等...),並且考慮到我決定遵循UAP原則,我會結束很多獲得者和制定者。我相信在這種情況下,如果我避免了獲得者和制定者,這沒有什麼不好,對吧? –

+0

@SavasVedova如果這個類只是一個數據結構,那麼* maybe *。但是我建議不要質疑你是否應該遵循它,而是要問你爲什麼不遵循它將來會證明你的代碼,並且很容易自動生成它們。 – Gordon

2

當一個變量被聲明爲public時,它可以從任何類訪問,使得程序員可以更容易地使用它;從而解釋你使用你描述的第二種方法的願望。但是,出於安全原因,某些變量需要聲明爲私有變量(也有時將其視爲一種好的做法)。我們宣佈他們是私人的這一事實使他們只能在自己的班級中進入。如果你需要在另一個類的函數中使用它們,那麼你需要遵循你描述的第一種方法 。

2

使用getter使其成爲只讀。

(這是唯一的概念上的差異。語言可以很容易地允許在性能方面以及方法來定義接口。命名約定並不是真正的基礎。)