“A class of which only a single instance can exist”
The Singleton pattern ensures that a class has only one instance and provides a global point of access to that instance. It is named after the singleton set, which is defined to be a set containing one element. The office of the President of the United States is a Singleton. The United States Constitution specifies the means by which a president is elected, limits the term of office, and defines the order of succession. As a result, there can be at most one active president at any given time. Regardless of the personal identity of the active president, the title, “The President of the United States” is a global point of access that identifies the person in the office.
Rules of thumb
- Abstract Factory, Builder, and Prototype can use Singleton in their implementation.
- Facade objects are often Singletons because only one Facade object is required.
- State objects are often Singletons.
- The advantage of Singleton over global variables is that you are absolutely sure of the number of instances when you use Singleton, and you can change your mind and manage any number of instances.
- The Singleton design pattern is one of the most inappropriately used patterns. Singletons are intended to be used when a class must have exactly one instance, no more, no less. Designers frequently use Singletons in a misguided attempt to replace global variables. A Singleton is, for intents and purposes, a global variable. The Singleton does not do away with the global; it merely renames it.
- When is Singleton unnecessary? Short answer: most of the time. Long answer: when it’s simpler to pass an object resource as a reference to the objects that need it, rather than letting objects access the resource globally. The real problem with Singletons is that they give you such a good excuse not to think carefully about the appropriate visibility of an object. Finding the right balance of exposure and protection for an object is critical for maintaining flexibility.
- Our group had a bad habit of using global data, so I did a study group on Singleton. The next thing I know Singletons appeared everywhere and none of the problems related to global data went away. The answer to the global data question is not, “Make it a Singleton.” The answer is, “Why in the hell are you using global data?” Changing the name doesn’t change the problem. In fact, it may make it worse because it gives you the opportunity to say, “Well I’m not doing that, I’m doing this” – even though this and that are the same thing.
Là một nhà tư vấn được trả lương hậu hĩnh tại MegaGigaco, bạn phải xử lý các sự cố về hiệu năng hệ thống. “Hệ thống hình như ngày càng chậm chạp hơn.” Các lập trình viên nói:
Tạo một đối tượng duy nhất với mẫu duy nhất Singleton.
Tạo lớp cơ sở dữ liệu Database dựa trên kiểu Singleton
Giờ là lúc bạn bắt tay vào viết mã nguồn. Bạn sẽ tạo một lớp tên Database mà các lập trình viên trong công ty sẽ sử dụng. Lớp này có một hàm khởi dựng đơn giản, như mã sau:
public class cDatabase
{
private int _record;
private string _name;
public cDatabase(string n)
{
_name = n;
_record = 0;
}
}
Bạn cần phải thêm vào hai hàm editRecord, cho phép bạn chỉnh sửa một bản ghi, và hàm getName, trả về tên gọi của Database.
public class cDatabase
{
private int _record;
private string _name;
public cDatabase(string n)
{
_name = n;
_record = 0;
}
public void editRecord(string operation)
{
Console.Writeln("Performing a: " + operation +
" opration on record: " + _record + " in a database: " + _name);
}
public string getName()
{
return _name;
}
}
Tới giờ mọi việc vẫn tốt đẹp. Bất cứ khi nào bạn tạo một đối tượng bằng toán tử new, một đối tượng mới sẽ được tạo ra. Nếu bạn tạo 3 database, bạn sẽ có 3 đối tượng như sau:
cDatabase dataone = new cDatabase(“products”);
cDatabase dataone = new cDatabase(“products Also”);
cDatabase dataone = new cDatabase(“products Again”);
Làm sao để bạn có thể tránh việc tạo một đối tượng mới khi sử dụng toán tử new? Đây là một giải pháp – làm cho hàm khởi dụng từ toàn cục (public) trở thành cục bộ (private)
private cDatabase(string n)
{
_name = n;
_record = 0;
}
Hãy xem đoạn mã sau:
public class cDatabase
{
private int _record;
private string _name;
private cDatabase(string n)
{
_name = n;
_record = 0;
}
}
public class cDatabase
{
private int _record;
private string _name;
private cDatabase(string n)
{
_name = n;
_record = 0;
}
public static cDatabase getInstance(string n)
{
}
}
public class cDatabase
{
private static cDatabase _singleObj;
private int _record;
private string _name;
private cDatabase(string n)
{
_name = n;
_record = 0;
}
public static cDatabase getInstance(string n)
{
if (_singleObj == null)
_singleObj = new cDatabase(n);
return _singleObj;
}
}
Khi bạn gọi getInstance lần nữa, bạn sẽ nhận được cùng một đối tượng như lần đầu.
Không quan tâm đến việc bạn gọi bao nhiêu lần getInstance, bạn luôn nhận được cùng một đối tượng. Đó chính là cách bạn phải làm với mẫu singleton.
Chạy thử ví dụ với mẫu Singleton
Bắt đầu bằng việc tạo một đối tượng Database với tên là products, sau đó gọi hàm getName:
public static void main()
{
cDatabase database;
database = cDatabase.getInstance("products");
Console.Writeline("This is the: " + cDatabase.getName() + " database");
}
Sau đó bạn tiếp tục tạo một đối tượng Database với tên là employees, và gọi lại hàm getName để kiểm tra:
public static void main()
{
cDatabase database;
database = cDatabase.getInstance("products")
Console.Writeline("This is the " + database.getName() + " database");
database = cDatabase.getInstace("employees");
Console.Writeline("This is the " + database.getName() + " database");
}
private static object _obj = new object();
public static cCustomer createInstance(string name)
{
// double check to avoid multiThreading
if (_singleObj == null)
{
lock (_obj)
{
if (_singleObj == null)
_singleObj = new cCustomer(name);
}
}
return _singleObj;
}
Ref:
https://sourcemaking.com/design_patterns/singleton
https://haihth.wordpress.com/2013/02/23/dp-chapter5/