2009-09-23 25 views
0

我的第一個問題基本上是要求代碼審查。我要提供的代碼是否使用Factory來促進多態性?它用PHP編寫。以下是基本要求:我使用工廠來促進多態性嗎?

  • 將長URL傳遞給庫,並且 返回縮短的URL。除了 長網址之外,還會將用戶屬性傳遞給 嘗試查找用戶特定的 縮短服務和API密鑰。
  • 允許用戶爲特定的網址縮寫設置API密鑰。我的代碼假設這已經在數據庫中設置,Bitly是唯一支持的服務。
  • 如果用戶沒有API密鑰和服務集,請使用默認的API密鑰和服務。同樣,我的代碼假定數據庫中的默認設置爲Bitly。
  • 如果url shortener服務失敗,請記錄失敗,但不要拋出異常。圖書館應該默默地失敗。我們將使用較長的網址,而不是使用較短的網址。

下面是調用代碼示例:

<?php 
$long_url = 'http://www.news.com/story/1'; 
$account_id = 1; 

$use_this_url = $long_url; 

$meta = array(
    'account_id' => $account_id, 
    // OPTIONS 
    // 'service_id' => $service_id, 
    // 'account_id' => $account_id, 
); 
$shortener = new Shortener_Factory($long_url, $meta); 
if ($shortener->shorten_long_url() AND $shortener->save_short_url()) 
{ 
       $use_this_url = $shortener->short_url;  
} 

echo $use_this_url; 

這裏是類:

<?php 
interface ShortenerServiceInterface { 
    public function save_short_url(); 
    public function shorten_long_url(); 
} 

abstract class ShortenerServiceAbstract implements ShortenerServiceInterface { 

    // Url to be shortened 
    public $long_url = ''; 

    // Long url unique id 
    public $url_id = 0; 

    // Service unique id 
    public $shorturlservice_id = 0; 

    // Service account unique id 
    public $shorturlserviceaccount_id = 0;  

    // Short url service unique API login 
    public $api_login = ''; 

    // Short url service unique API key 
    public $api_key = ''; 

    // Short url service unique hash which maps to original url value 
    public $hash = ''; 

    // Shortened url string 
    public $short_url = ''; 


    // Attempt to call shortner service three times before failing 
    public $attempts = 3; 

    // Shorten long url with specific service API/logic 
    public function shorten_long_url() 
    { 
     // Can't save a short url when one doesn't exist 
     if (!$this->long_url OR !$this->api_login OR !$this->api_key) { 
      log('error', 'ShortenerServiceAbstract::shorten_long_url - no long url to shorten - '.var_export($this, TRUE)); 
      return FALSE; 
     }   
    } 

    // Save short url and related meta-data to shorturls table 
    public function save_short_url() 
    { 
     // Can't save a short url when one doesn't exist 
     if (!$this->url_id OR !$this->hash OR !$this->shorturlservice_id OR !$this->shorturlserviceaccount_id) { 
      log('error', 'ShortenerServiceAbstract::save_short_url - no short url to save - '.var_export($this, TRUE)); 
      return FALSE; 
     } 

     // Insert a new short url, or update an existing record 
     $saved = Shorturl_Model::insert_on_dup_key_update($this->url_id, $this->hash, $this->shorturlservice_id, $this->shorturlserviceaccount_id); 

     if (!$saved) { 
      log('error', 'ShortenerServiceAbstract::save_short_url - short url record can not be saved - '.var_export($this, TRUE)); 
      return FALSE; 
     } else { 
      return TRUE; 
     }   
    } 

} 

// Bitly, a simple url shortener 
// @link http://code.google.com/p/bitly-api/wiki/ApiDocumentation 
class ShortenerServiceBitly extends ShortenerServiceAbstract { 

    public function shorten_long_url() 
    { 
     // Make sure we have required members set 
     parent::shorten_long_url(); 

     $urlencoded = urlencode($this->long_url); 
     $bitlyurl = 'http://api.bit.ly/shorten?version=2.0.1&longUrl='.$urlencoded.'&login='.$this->api_login.'&apiKey='.$this->api_key.'&history=1'; 

     $attempts = 1; 
     while ($attempts <= 3) { 
      $json_result = file_get_contents($bitlyurl);   
      if ($json_result) {         
       // Return an assoc array 
       $json_decode = json_decode($json_result, TRUE); 
       if (is_array($json_decode) AND isset($json_decode['errorCode']) AND $json_decode['errorCode'] == 0) { 
        // Don't compare sent URL with returned URL 
        // Bitly removes invalid poritions of URLs 
        // The camparison might fail even though the URLs are the "same" 
        $shortened = current($json_decode['results']); 
        break; 
       } else { 
        log('error', 'ShortenerServiceBitly::shorten_long_url - bit.ly json decoded - '.var_export($json_decode, TRUE)); 
       } 
      } else { 
        log('error', 'ShortenerServiceBitly::shorten_long_url - bit.ly http response - '.var_export($json_result, TRUE)); 
      } 
      $attempts++; 
     } 

     if (isset($shortened)) { 
      $this->short_url = $shortened['shortUrl']; 
      $this->hash = $shortened['userHash']; 
      return TRUE; 
     } else { 
      return FALSE; 
     } 
    } 

} 

// Shortener Factory 
class Shortener_Factory { 

    // Shortener service account parameter object 
    // @param object shortener account properties 
    private $_account; 

    // Shortener service object created by factory 
    //@param object shorterner service functions 
    private $_service; 

    // Url to be shortened 
    private $_long_url; 

    // Set url members, service parameter object and finally the service itself 
    public function __construct($long_url, $meta=array()) 
    { 
     $this->_long_url = $long_url; 

     $this->_set_account($meta); 
     $this->_set_service();     
    } 

    // Set shortener service account parameter object 
    // @param $meta array determine parameters for the current service object 
    private function _set_account($meta=array()) 
    {      
     $s = FALSE; 

     // Get shorturl service account 
     if (isset($meta['account_id'])) { 
      $s = Shorturlserviceaccount_Model::get_by_account_id($meta['account_id']); 
     } elseif (isset($meta['service_id'])) { 
      $s = Shorturlserviceaccount_Model::get_by_service_id($meta['service_id']); 
     } 

     // Account not found, lets use default 
     if (!$s) { 
      $s = Shorturlserviceaccount_Model::get_default(); 
     } 

     // Must have a service to use 
     if ($s === FALSE) { 
      log('error', 'Shortener_Core::_set_account - _account not found - '.var_export($this, TRUE)); 
      return FALSE; 
     } else { 
      $this->_account = $s; 
     }   
    } 

    // Use shortener service account parameter object to set shortener service object 
    private function _set_service() 
    { 
     switch ($this->_account->name) { 
      case 'bitly': 
       $this->_service = new ShortenerServiceBitly; 
    break; 
      default: 
       log('error', 'Shortener_Core::_set_service - _account not set - '.var_export($this, TRUE)); 
    return FALSE; 
     } 

     $this->_service->long_url = $this->_long_url;   
     $this->_service->shorturlserviceaccount_id = $this->_account->id;  
     $this->_service->shorturlservice_id = $this->_account->shorturlservice_id; 
     $this->_service->api_login = $this->_account->api_login; 
     $this->_service->api_key = $this->_account->api_key; 
    } 

    // Public API for shortener service object methods 
    public function __call($name, $arguments) 
    { 
     if (!$this->_service) { 
       log('error', 'Shortener_Core::__call - _service not set - '.var_export($this, TRUE)); 
    return FALSE;    
     } 
     return $this->_service->$name(); 
    } 

    // Public API for shortener service object members 
    public function __get($name) 
    { 
     return ($this->_service->$name) ? $this->_service->$name : NULL; 
    } 
} 
+0

您的設計和代碼看起來不錯。你問什麼功能或部分具體作爲工廠? – philfreo 2009-12-27 04:23:31

回答

0

工廠模式的工作是抽象掉對象的創建。這是有用的原因是因爲創建對象的方式可能與剛創建的方式不同:

$instance = new Object(); 

您隨時創建它。例如,如果您首先需要處理加載包含文件,或者您需要根據運行時未知的某些參數從幾個派生類中選擇一個。

一個工廠可以像下面的那樣簡單:

function getInstance($objectType, $params) 
{ 
    if (!class_exists($objectType)) { 
     throw new Exception('Bad class'); 
    } 
    $instance = new $objectType($params); 
    return $instance; 
} 

,或者可以像你一樣複雜,但這些都是基本的規律可循。看看這裏的維基百科文章PHP示例