2016-05-30 54 views
-1

有關於這個話題多了,但我沒有,爲什麼工廠模式比單件更好的做法清晰的畫面。辛格爾頓工廠在PHP

一個例子

class MySingleton { 
public static function numberByWhat($number) { 
    return $number + 100; 
} 
public static function someCharacters($string) { 
    return $string + 'abc'; 
} 
} 

class MyOtherSingleton { 
    public static function getImage($url) { 
    return '<img src="' . $url . MySingleton::numberByWhat($50) . '">'; 
    } 
    public static function getTextById($id) { 
    if($id == 3) { 
     return 'this is my text' . MySingleton::someCharacters('Yeah'); 
    } 
    } 
} 

function run() { 
    echo MyOtherSingleton::getImage('http://www.example.com/image.png'); 
    echo MyOtherSingleton::getTextById(3); 
} 

run(); 

因此,我們有2類和函數。當我run()我在第二課中開始一個功能。在第二類的函數內部有對第一類的調用。

  • 這看起來像一個工廠模式?
  • 爲什麼是它作爲一個工廠模式更好?
+3

這看起來不像工廠或單件模式。現在,您只需將一些功能分組在某些類中。很難測試你的類實例的狀態。 – mauris

+1

'工廠'創建一些對象。你的代碼在哪裏有對象? –

+0

你可以在這個例子中完全刪除類,並使用簡單的原始全局函數。類在這裏添加的唯一東西是一些命名空間。你沒有任何實際的面向對象的領域,因此這個問題沒有什麼意義。 – deceze

回答

3

所以,你給出的例子既不是單身,也沒有工廠。你在這裏只是簡單的「靜態類」 - 只有靜態方法和屬性的類。工廠和單身人士也不能真正解決同樣的問題,因此很難比較和比較它們。

單身

一個Singleton用於管理共享狀態或者避免多次實例化一個類的開銷,當你只有真正需要「的東西之一。」

這裏是一個單身的例子:

class DatabaseConnection { 
    // Static reference to the single instance of this class we maintain. 
    protected static $instance; 

    // Normal instance properties. 
    protected $mysql; 

    // Protected constructor to prevent "new DatabaseConnection();" 
    protected function __construct() { 
     $this->mysql = new MySQLConnection("localhost", 3306, "appdb"); 
    } 

    public static function getInstance() { 
     if (!self::$instance) { 
      self::$instance = new self(); 
     } 

     return self::$instance; 
    } 

    public function query($sql) { 
     return $this->mysql->query($sql); 
    } 
} 

每當你想在你的代碼中使用了DatabaseConnection(),你做這樣的:

function getUser($userId) { 
    $userData = DatabaseConnection::getInstance()->query("SELECT * FROM ..."); 
} 

DatabaseConnection()只實例化一次,開始第一次使用它。永遠不會有超過一個創建。

依賴注入/控制

的競爭戰略使用一個Singleton反轉是,基本上,Dependency InjectionInversion of Control。與依賴注入,而不是具有一個共享的,一類staticly-存儲的實例,該實例僅僅是通過從類類和函數起作用。這裏有一個簡單的例子:

依賴注入的
class DatabaseConnection { 
    // Normal instance properties. 
    protected $mysql; 

    public function __construct() { 
     $this->mysql = new MySQLConnection("localhost", 3306, "appdb"); 
    } 

    public function query($sql) { 
     return $this->mysql->query($sql); 
    } 
} 

class UserManager { 
    protected $databaseConnection; 

    public function __construct(DatabaseConnection $databaseConnection) { 
     $this->databaseConnection = $databaseConnection; 
    } 

    public function lookupUser($userId) { 
     return $this->databaseConnection->query("SELECT ..."); 
    } 
} 

一個好處是,你可以更容易地測試你的代碼。你可以,例如,延長DatabaseConnection並調用它TestDatabaseConnection,使之不能實際使用一個真正的MySQL數據庫,它可以使你的測試更快,更可靠。所以,爭論是在單身人士和依賴注入/控制反轉之間,而不是工廠之間。

工廠

所以,現在,Factories:工廠簡化對象的創建,返回不同的類/子類的對象,並有助於從「模板」創建對象。舉個例子,假設我們有不同的類來表示用戶的不同的類型:

class User { 
    // ... 
} 

class ModeratorUser extends User { 
    // ... 
} 

class AdminUser extends ModeratorUser { 
    // ... 
} 

class GuestUser extends User { 
    // ... 
} 

這些類包含的方法和屬性,這將是與某種類型的用戶帳戶的工作是有用的。那麼,您將如何通過用戶ID創建並返回其中一個用戶對象,確保返回正確類型的用戶?我們可以用一個工廠模式:

class UserFactory { 
    public static function fromUserId(DatabaseConnection $db, $userId) { 
     $record = $db->query("SELECT * FROM users WHERE user_id ..."); 
     // ... 

     switch ($record['type']) { 
      case 'admin': 
       return new AdminUser($userId); 
       break; 

      case 'moderator': 
       return new ModeratorUser($userId); 
       break; 

      case 'guest': 
       return new GuestUser($userId); 
       break; 

      default: 
      case 'normal': 
       return new User($userId); 
       break; 
     } 
    } 
} 

然後,加載正確的User類,你只要致電:

$user = UserFactory::fromUserId($userId); 

如果是管理員帳戶,這將是一個AdminUser;如果它是一個訪客帳戶,它將是一個GuestUser

+0

因此,在最後一個...靜態函數調用使用一種基類的擴展類。這可能是迄今爲止我見過的最簡單的例子。我從現在開始可能會將靜態函數與擴展類結合起來。 –