2009-11-30 30 views
18

Nếu bạn đã có một lớp nhà máy tạo ra các đối tượng mới của một số loại, và rằng lớp factroy là một singleton, như thế này:Mở rộng abstract class singleton

class Database_Factory extends Base_Factory { 
    private static $factory; 
    private $objects = array(); 

    public function __get($profile) { 
     // check for object and return it if it's created before 
    } 

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

Các lặp đi lặp lại cùng một mã bất cứ lúc nào, nơi một số đối tượng cần nó riêng nhà máy. Vì vậy, tôi quyết định làm cho lớp nhà máy này trừu tượng và chỉ thực hiện các quy trình cụ thể cho từng nhà máy. Nhưng PHP không cho phép khởi tạo lớp trừu tượng.

abstract class Base_Factory { 
    public static function getInstance(){ 
     if (!self::$factory) 
      self::$factory = new self(); 
     return self::$factory; 
    } 
} 

Fatal error: Không thể nhanh chóng abstract class Base_Factory

bạn sẽ làm gì?

+0

Câu hỏi cơ bản là: làm thế nào để tôi tự do bản thân mình bằng cách viết những getInstance (và có thể sau này một số chi tiết) chức năng trong mỗi nhà máy? –

Trả lời

29

Trong phương pháp PHP, self luôn đề cập đến lớp mà phương pháp được định nghĩa. Kể từ phiên bản 5.3.0, PHP hỗ trợ "liên kết tĩnh muộn", nơi bạn có thể sử dụng từ khóa static để truy cập các phương thức tĩnh được ghi đè, cũng như hàm get_called_class() để lấy tên của lớp dẫn xuất trong ngữ cảnh tĩnh.

Tuy nhiên, thiết kế của bạn có một lỗ hổng lớn: Thuộc tính tĩnh $factory được xác định trong Base_Factory được chia sẻ trên tất cả các lớp dẫn xuất. Vì vậy, lần đầu tiên một singleton được tạo ra và được lưu trữ trong thuộc tính này, tất cả các cuộc gọi khác đến getInstance() sẽ trả về cùng một đối tượng, bất kể lớp dẫn xuất được sử dụng.

Bạn có thể sử dụng một tên lớp điển ánh xạ tĩnh để Singleton đối tượng:

abstract class Base_Factory { 
    private static $_instances = array(); 
    public static function getInstance() { 
     $class = get_called_class(); 
     if (!isset(self::$_instances[$class])) { 
      self::$_instances[$class] = new $class(); 
     } 
     return self::$_instances[$class]; 
    } 
} 

Ồ, một điều nữa: Thực tế là bạn đang tìm kiếm một khả năng tái sử dụng mã cho đối tượng singleton có thể là một cue thực tế là bạn đang sử dụng quá mức mẫu thiết kế singleton! Hãy tự hỏi bản thân xem các lớp bạn đang lên kế hoạch thực hiện như những người độc thân thực sự là những người độc thân và nếu không có trường hợp sử dụng nào mà bạn có thể muốn có nhiều phiên bản của một lớp cụ thể.

Thường thì tốt hơn hết là chỉ sử dụng một singleton đại diện cho "ngữ cảnh ứng dụng" hiện tại cung cấp các trình truy cập cho các đối tượng là các trình đơn liên quan đến ngữ cảnh này.

+0

Cảm ơn, nhưng unfortunatelly tôi không có PHP> = 5.3 trên lưu trữ được chia sẻ của tôi vào lúc này. Nhưng tôi sẽ giữ mã này cho những lần tôi sẽ :). –

+1

Bạn quên khai báo $ _instances là tĩnh – clu3

+0

@ clu3 - Cảm ơn. –

-2

Bạn có thể kiểm tra để chắc chắn rằng lớp đang gọi hàm không phải là Base_Factory.

if(__CLASS__!='Base_Factory') 

Sau đó, sử dụng $ this thay vì tự tham chiếu đến đối tượng hiện tại thay vì lớp hiện tại.

if (!$this->factory) 
     $this->factory = new self(); 
    return $this->factory; 
+1

Các hàm tĩnh không có '$ this'. Hơn nữa, '__CLASS__' luôn đại diện cho lớp mà một hàm được định nghĩa, trong trường hợp của bạn, nó sẽ luôn là 'Base_Factory', ngay cả trong các lớp dẫn xuất. –

+0

Ah xin lỗi quyền của bạn, bạn thậm chí không thể sử dụng get_class ($ this) như là một thay thế. – Shane

-1

Theo định nghĩa lớp trừu tượng không thể được khởi tạo trong PHP như bất kỳ ngôn ngữ hướng đối tượng nào khác. Vì vậy, Base_Factory của bạn nên là giao diện thay vì lớp trừu tượng.

Từ hướng dẫn sử dụng PHP: "Không được phép tạo một thể hiện của một lớp đã được định nghĩa là trừu tượng".

+1

Mark dường như biết rằng ông không thể khởi tạo lớp cơ sở trừu tượng của mình. Hew muốn tự động khởi tạo các lớp bắt nguồn, không trừu tượng từ mã được định nghĩa trong lớp cơ sở trừu tượng. –

+0

Có Ferdinand, đó là chính xác. –

4

PHP> = 5,3 chỉ

abstract class Base_Factory { 
    protected static $factory; 
    public static function getInstance(){ 
     if (!self::$factory) { 
      $class = get_called_class(); 
      self::$factory = new $class(); 
     } 
     return self::$factory; 
    } 
} 
+0

+1 Nó hoạt động. Vậy tại sao chúng ta tạo một từ điển như trong câu trả lời được chấp nhận từ @FerdinandBeyer? Tôi nghĩ chỉ khi chúng ta muốn có nhiều cá thể đơn lẻ từ cùng một lớp trừu tượng, đúng không? –

+1

Ý tưởng thú vị, nhưng điều này không hoạt động trong PHP7. – SalientGreen

+1

Cập nhật: hoặc trong PHP 5.3 cho cùng một lý do như được mô tả trong câu trả lời được chấp nhận. self :: $ factory sẽ được định nghĩa khi bất kỳ lớp dẫn xuất nào được khởi tạo. – SalientGreen

1

đăng ký độc thân của bạn trong một lớp học đơn giản như thế này

class Singletons { 
    static private $singleton = array(); 
    public function getSingleton($class) { 
    if (!isset(self::$singleton[$class])) { 
     self::$singleton[$class] = new $class; 
    } 
    return self::$singleton[$class]; 
    } 
} 

Sau đó làm

class aSingleton { 
    public $i; 
    public function test() { 
    ++$this->i; 
    echo get_class() . " called {$this->i} times\n"; 
    } 
} 

Singletons::getSingleton('aSingleton')->test(); 
Singletons::getSingleton('aSingleton')->test(); 

Output này

aSingleton called 1 times 
aSingleton called 2 times 
+0

Có thể bạn sẽ phải có một biến thành viên tĩnh theo dõi ví dụ đơn lẻ của aSingleton. –

8

PHP 5.3+

abstract class Singleton 
{ 
    /** 
    * Instance 
    * 
    * @var Singleton 
    */ 
    protected static $_instance; 

    /** 
    * Constructor 
    * 
    * @return void 
    */ 
    protected function __construct() {} 

    /** 
    * Get instance 
    * 
    * @return Singleton 
    */ 
    public final static function getInstance() { 
     if (null === static::$_instance) { 
      static::$_instance = new static(); 
     } 

     return static::$_instance; 
    } 
} 
Các vấn đề liên quan