所以你给出的例子既不是单例也不是工厂。您在这里拥有的只是“静态类”——只有静态方法和属性的类。工厂和单例也不能真正解决同一个问题,因此很难对它们进行比较和对比。
单身人士
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() 仅在第一次使用时实例化一次。永远不会创建超过一个。
依赖注入/控制反转
使用单例的竞争策略基本上是Dependency Injection 或Inversion of Control。使用依赖注入,不是拥有一个共享的、静态存储的类实例,而是简单地将实例从类传递到类和函数到函数。这是一个简单的例子:
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。