Advertisement
  1. Code
  2. Design Patterns

Thiết kế Patterns: Mô hình Singleton

Scroll to top
Read Time: 8 min

() translation by (you can also view the original English article)

Trong bài này bạn sẽ tìm hiểu làm thế nào để thực hiện các mẫu thiết kế Singleton, và lý do tại sao và khi nào thì sử dụng mô hình này trong các ứng dụng của bạn. Như tên gọi "Singleton" cho thấy, phương pháp này cho phép chúng tôi để tạo ra một và chỉ có một đối tượng của một lớp học.

Hãy xem những gì chúng tôi có trên Wikipedia về mẫu thiết kế này:

Các mô hình singleton là một mẫu thiết kế hạn chế instantiation một lớp học vào một đối tượng. Điều này rất hữu ích khi một đối tượng là cần thiết để phối hợp hành động trên hệ thống.

Như đã đề cập trong định nghĩa ở trên, khi chúng tôi muốn đảm bảo rằng một và chỉ có một đối tượng cần được tạo ra cho bất kỳ lớp học, sau đó chúng ta nên thực hiện các mô hình Singleton cho lớp đó.

Bạn có thể hỏi lý do tại sao chúng tôi nên thực hiện một lớp mà cho phép chúng tôi để tạo ra các đối tượng duy nhất của nó. Tôi muốn nói có rất nhiều trường hợp mà chúng tôi có thể áp dụng mẫu thiết kế này sử dụng. Chúng bao gồm: cấu hình lớp học, phiên họp lớp, lớp cơ sở dữ liệu và nhiều hơn nữa.

Tôi sẽ lấy ví dụ một lớp cơ sở dữ liệu cho bài viết này. Lần đầu tiên chúng ta sẽ thấy những gì các vấn đề có thể nếu một mẫu Singleton không được thực hiện cho một lớp học.

Các vấn đề

Hãy tưởng tượng một lớp học kết nối cơ sở dữ liệu rất đơn giản mà tạo ra một kết nối với cơ sở dữ liệu sau khi chúng tôi tạo ra một đối tượng của lớp đó.

1
class database {
2
    
3
  private $dbName = null, $dbHost = null, $dbPass = null, $dbUser = null;
4
	
5
	public function __construct($dbDetails = array()) {
6
		
7
		$this->dbName = $dbDetails['db_name'];
8
		$this->dbHost = $dbDetails['db_host'];
9
		$this->dbUser = $dbDetails['db_user'];
10
		$this->dbPass = $dbDetails['db_pass'];
11
12
		$this->dbh = new PDO('mysql:host='.$this->dbHost.';dbname='.$this->dbName, $this->dbUser, $this->dbPass);
13
		
14
	}
15
	
16
}

Trong ví dụ mã trên, bạn có thể thấy rằng nó sẽ làm cho một kết nối đến cơ sở dữ liệu mỗi khi bạn tạo một đối tượng của lớp học này. Vì vậy nếu một nhà phát triển đã tạo ra một đối tượng của lớp học này ở nhiều nơi, tưởng tượng số lượng các kết nối cơ sở dữ liệu (giống hệt nhau) nó sẽ tạo ra với các máy chủ cơ sở dữ liệu.

Vì vậy không biết nhà phát triển là làm cho những sai lầm mà dẫn đến một tác động rất lớn vào tốc độ của cơ sở dữ liệu và máy chủ ứng dụng. Chúng ta hãy xem những điều tương tự thông qua việc tạo ra một đối tượng khác nhau của lớp đó.

1
$dbDetails = array(
2
    	'db_name' => 'designpatterns',
3
		'db_host' => 'localhost',
4
		'db_user' => 'root',
5
		'db_pass' => 'mysqldba'
6
);
7
8
$db1 = new database($dbDetails);
9
var_dump($db1);
10
$db2 = new database($dbDetails);
11
var_dump($db2);
12
$db3 = new database($dbDetails);
13
var_dump($db3);
14
$db4 = new database($dbDetails);
15
var_dump($db4);
16
17
// Output

18
object(database)[1]
19
  private 'dbName' => string 'designpatterns' (length=14)
20
  private 'dbHost' => string 'localhost' (length=9)
21
  private 'dbPass' => string 'mysqldba' (length=8)
22
  private 'dbUser' => string 'root' (length=4)
23
  public 'dbh' => object(PDO)[2]
24
object(database)[3]
25
  private 'dbName' => string 'designpatterns' (length=14)
26
  private 'dbHost' => string 'localhost' (length=9)
27
  private 'dbPass' => string 'mysqldba' (length=8)
28
  private 'dbUser' => string 'root' (length=4)
29
  public 'dbh' => object(PDO)[4]
30
object(database)[5]
31
  private 'dbName' => string 'designpatterns' (length=14)
32
  private 'dbHost' => string 'localhost' (length=9)
33
  private 'dbPass' => string 'mysqldba' (length=8)
34
  private 'dbUser' => string 'root' (length=4)
35
  public 'dbh' => object(PDO)[6]
36
object(database)[7]
37
  private 'dbName' => string 'designpatterns' (length=14)
38
  private 'dbHost' => string 'localhost' (length=9)
39
  private 'dbPass' => string 'mysqldba' (length=8)
40
  private 'dbUser' => string 'root' (length=4)
41
  public 'dbh' => object(PDO)[8]

Nếu bạn thấy đầu ra của các mã và sản lượng trên, bạn có thể thấy rằng mỗi đối tượng có một ID tài nguyên mới được chỉ định, vì vậy tất cả đối tượng là tài liệu tham khảo hoàn toàn mới, do đó nó phân bổ bộ nhớ riêng biệt như là tốt. Vì vậy không biết ứng dụng của chúng tôi sẽ chiếm tài nguyên đó là thực sự không cần thiết.

Các giải pháp

Nó không phải là trong kiểm soát của chúng tôi như thế nào các nhà phát triển sử dụng khung cơ sở của chúng tôi. Đó là trong kiểm soát của chúng tôi sau khi quá trình xem xét mã diễn ra, nhưng trong quá trình phát triển chúng tôi không thể đứng đằng sau họ tất cả thời gian.

Để khắc phục tình hình như vậy, chúng ta nên lớp cơ sở của chúng tôi theo một cách rằng nó là không thể tạo ra nhiều đối tượng của một lớp học; thay vào đó nó sẽ cung cấp cho một đối tượng đã tạo ra nếu bất kỳ. Đây là lý do mà chúng ta nên xem xét việc phát triển một mẫu Singleton cho các lớp học cơ sở.

Trong khi thực hiện mô hình này, mục tiêu của chúng tôi sẽ cho phép tạo ra một đối tượng của một lớp một và chỉ một thời gian. Cho phép tôi để thêm mã lớp dưới đây và sau đó chúng ta sẽ đi qua từng phần của lớp học này.

1
class database {
2
    
3
	private $dbName = null, $dbHost = null, $dbPass = null, $dbUser = null;
4
	private static $instance = null;
5
	
6
	private function __construct($dbDetails = array()) {
7
		
8
		// Please note that this is Private Constructor

9
		
10
		$this->dbName = $dbDetails['db_name'];
11
		$this->dbHost = $dbDetails['db_host'];
12
		$this->dbUser = $dbDetails['db_user'];
13
		$this->dbPass = $dbDetails['db_pass'];
14
15
		// Your Code here to connect to database //

16
		$this->dbh = new PDO('mysql:host='.$this->dbHost.';dbname='.$this->dbName, $this->dbUser, $this->dbPass);
17
	}
18
	
19
	public static function connect($dbDetails = array()) {
20
		
21
		// Check if instance is already exists 		

22
		if(self::$instance == null) {
23
			self::$instance = new database($dbDetails);
24
		}
25
		
26
		return self::$instance;
27
		
28
	}
29
	
30
	private function __clone() {
31
		// Stopping Clonning of Object

32
	}
33
	
34
	private function __wakeup() {
35
		// Stopping unserialize of object

36
	}
37
	
38
}

Đó là dấu hiệu cho thấy ít nói rằng các lớp học ở trên là một lớp Singleton. Điều đầu tiên là một nhà xây dựng tư nhân, ngăn chặn các đối tượng sáng tạo bằng cách sử dụng các từ khóa mới. Một dấu hiệu là một trong những thành viên tĩnh biến giữ chức tham chiếu đến một đối tượng đã tạo ra.

1
$dbDetails = array(
2
    	'db_name' => 'designpatterns',
3
		'db_host' => 'localhost',
4
		'db_user' => 'root',
5
		'db_pass' => 'mysqldba'
6
);
7
8
$db1 = database::connect($dbDetails);
9
var_dump($db1);
10
$db2 = database::connect($dbDetails);
11
var_dump($db2);
12
$db3 = database::connect($dbDetails);
13
var_dump($db3);
14
$db4 = database::connect($dbDetails);
15
var_dump($db4);
16
17
// Output

18
19
object(database)[1]
20
  private 'dbName' => string 'designpatterns' (length=14)
21
  private 'dbHost' => string 'localhost' (length=9)
22
  private 'dbPass' => string 'mysqldba' (length=8)
23
  private 'dbUser' => string 'root' (length=4)
24
  public 'dbh' => object(PDO)[2]
25
object(database)[1]
26
  private 'dbName' => string 'designpatterns' (length=14)
27
  private 'dbHost' => string 'localhost' (length=9)
28
  private 'dbPass' => string 'mysqldba' (length=8)
29
  private 'dbUser' => string 'root' (length=4)
30
  public 'dbh' => object(PDO)[2]
31
object(database)[1]
32
  private 'dbName' => string 'designpatterns' (length=14)
33
  private 'dbHost' => string 'localhost' (length=9)
34
  private 'dbPass' => string 'mysqldba' (length=8)
35
  private 'dbUser' => string 'root' (length=4)
36
  public 'dbh' => object(PDO)[2]
37
object(database)[1]
38
  private 'dbName' => string 'designpatterns' (length=14)
39
  private 'dbHost' => string 'localhost' (length=9)
40
  private 'dbPass' => string 'mysqldba' (length=8)
41
  private 'dbUser' => string 'root' (length=4)
42
  public 'dbh' => object(PDO)[2]

Nếu bạn so sánh sản lượng của cả hai phần sau đó bạn sẽ thấy, ở đầu ra của các mô hình Singleton, các ID tài nguyên cho các đối tượng là giống nhau cho tất cả các đối tượng khác nhau. Nhưng đó không phải là trường hợp khi mẫu thiết kế không được sử dụng.

Singleton như là một mô hình chống

Mẫu thiết kế này còn được gọi là một mô hình chống vì nhiều lý do, tôi sẽ đề cập đến dưới đây:

  1. Nó vi phạm các nguyên tắc trách nhiệm duy nhất vì nó có chất lượng của việc kiểm soát sáng tạo và vòng đời của riêng mình.
  2. Nó giới thiệu nhà nước toàn cầu ứng dụng của bạn. Tôi muốn nói nhà nước toàn cầu là rất xấu, vì bất kỳ mã có thể thay đổi giá trị của nó. Vì vậy khi gỡ lỗi đó là thực sự khó khăn để tìm phần của mã đã thực hiện trong giai đoạn hiện nay của toàn cầu biến.
  3. Singleton nói chung là một ý tưởng xấu nếu bạn đang làm đơn vị thử nghiệm, và nó nói chung là một ý tưởng xấu không phải là để thực hiện các đơn vị kiểm tra.

Kết luận

Tôi đã cố gắng tốt nhất của tôi để giải thích các mẫu thiết kế Singleton, thảo luận rộng rãi trên internet. Tôi hy vọng bạn tìm thấy bài viết này hữu ích. Chúng tôi đã bao phủ cả hai khía cạnh của mô hình này như là một mẫu thiết kế và như là một mô hình chống.

Xin vui lòng gửi ý kiến của bạn, đề nghị và/hoặc câu hỏi dưới đây, và tôi sẽ đăng bài phản ứng của tôi càng sớm càng tốt. Bạn cũng có thể tiếp cận với tôi trên Twitter @XpertDevelopers hoặc gửi email cho tôi ngay lập tức.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.