面向對象的設計強調「抽象類高於實踐」,儘量的將代碼設計的通常化,而非特殊化——也就是下降耦合,提高標準性。因而,前輩們便設計了「特定類處理實例化」的工廠方法。segmentfault
Appointment
類須要解析BloggsCal
數據格式,在類內部,咱們將數據格式寫死爲BloggsCal
,這將會形成耦合,並且實際上,將來業務需求要面臨更多的數據格式。設計模式
這個時候咱們引入工廠方法模式,設置CommsManager
類(創造者,creater)、ApptEncoder
類(產品,Product)。架構
接下來,用戶只須要調用CommsManager
對象的getApptEncoder
方法,就能夠獲得他們須要的對象,而無需關注這個對象究竟是哪一種數據格式。app
abstract class ApptEncoder { abstract function encode(); } class BloggsApptEncoder extends ApptEncoder { function encode() { return "數據格式爲BloggsCal。"; } } class MegaApptEncoder extends ApptEncoder { function encode() { return "數據格式爲MegaCal。"; } } class CommsManager { const BLOGGS = 1; const MEGA = 2; private $mode = 1; function __construct( $mode ) { $this->mode = $mode; } function getApptEncoder() { switch ( $this->mode ) { case ( self::MEGA ) : return new MegaApptEncoder(); default: return new BloggsApptEncoder(); } } function getHeaderText() { switch ( $this->mode ) { case ( self::MEGA ): return "Mega格式的表頭"; default: return "BloggsCal格式的表頭"; } } function getFootText() { switch ( $this->mode ) { case ( self::MEGA ): return "Mega格式的腳頁"; default: return "BloggsCal格式的腳頁"; } } } $comms = new CommsManager( CommsManager::MEGA ); $apptEncoder = $comms->getApptEncoder(); echo $apptEncoder->encode();
注意到CommsManager
類的三個getXXX
方法了嗎?this
一旦數據格式增多、功能增長、數據格式間存在業務差別,就會形成一個新問題:大量的判斷語句——包括我本身在內的一些人認爲,這是代碼腐爛的象徵。設計
至少,當重複的代碼開始蔓延,咱們不該該感到樂觀。(儘管下面的處理方法,在必定程度上也重複了這個錯誤)code
面對上述難題,咱們有了下列三條要求:面向對象設計模式
在代碼運行時,才能瞭解咱們要生成的對象類型(實時傳參,注意那句:$comms = new CommsManager( CommsManager::MEGA )
);對象
相對輕鬆的加入新數據格式(Product);get
每一個產品類型都能輕鬆加入訂製化功能。
既然如此,咱們乾脆將 數據格式們 從CommsManager
中剝離出來,造成單獨的子類。
// 產品抽象類、子類的代碼,同上。 abstract class CommsManager { abstract function getApptEncoder(); abstract function getHeaderText(); abstract function getFooterText(); } class BloggsCommsManager extends CommsManager { function getApptEncoder() { return new BloggsApptEncoder(); } function getHeaderText() { return "BloggsCal格式的表頭"; } function getFooterText() { return "BloggsCal格式的腳頁"; } } class MegaCommsManager extends CommsManager { function getApptEncoder() { return new MegaApptEncoder(); } function getHeaderText() { return "MegaCal格式的表頭"; } function getFooterText() { return "MegaCal格式的腳頁"; } } $comms = new BloggsCommsManager(); $apptEncoder = $comms->getApptEncoder(); echo $apptEncoder->encode();
這樣知足了上述的三個要求,可我想,聰明的你已經注意到了:必定程度上,建立者/產品
們 產生了代碼重複。並且,問題被轉移到了工廠方法中,咱們目前只是處理了Appointment
功能,若是咱們加入TodoList
功能呢?
答案很明顯,咱們須要:能夠同時處理一組相關實現的架構,解決之道就在下一篇文章:抽象工廠模式。