今天要講設計模式中最為常見的Pattern!
Singleton is a creational design pattern that lets you ensure that a class has only one instance, while providing a global access point to this instance.
-- Refactoring Guru
Singleton Pattern--單例模式
它限制了每一個class的初始化,並保證一個class裡只有一個instance可以被創建
我們先來看它的UML吧~
Singleton class宣告了一個靜態方法getInstance
,該方法返回其自身class的同一instance。
Singleton的建構子(constructor)應該對client端的code做隱藏。呼叫getInstance
方法應該是獲得Singleton物件的唯一方式。
Singleton設計模式是為了解決以下主要問題而出現的:
當需要全域中唯一的Instance:
在某些情況下,應用程式需要確保只有一個instance存在,以協調各種操作或資源的訪問。
例如,當需要管理global的系統設定、資料庫的連接、儲存或讀取記錄時,這種需求變得非常重要。
Singleton模式確保只有一個唯一的instance,這樣就可以和global共享或是訪問這個instance,而不需要重複創建或管理多個instances。
避免資源浪費:
如果某個類別的instance在應用程式中多次創建,可能會導致資源浪費,例如記憶體。
Singleton模式的延遲初始化特性確保instance只在需要時才被創建,從而減少了資源消耗。
確保唯一性:
在某些情況下,需要確保某個物件的唯一性,以避免多個Instance導致不一致的狀態。
Singleton模式可以確保只有一個instance存在,因此可以讓它維持一樣的狀態。
單例模式在以下情況會出現:
Unique Access Point: 當希望有個單一存取點來訪問一個instance時,單例模式提供了一個明確且可控的方式。
若沒有單一訪問點會像下圖一樣~ 客戶端也許不會發現他們正在和同一個物件溝通
-- 圖片來源: Refactoring Guru
共享資源: 當系統的多個部分需要共享相同的資源(例如config data、loggin service或cache)時,單例確保它們都使用相同的instance,以維持一致性。
狀態維護: 如果需要在多個consumer之間保持一致的狀態,單例可以通過 提供一個單一的具有狀態的instance來幫助實現。
資源密集型物件: 當創建一個物件需要耗時、資源密集或僅需要初始化一次時,使用單例可以確保該物件只有被實例化一次並在之後重複使用。
硬體訪問控制: 對於訪問硬體界面(如印表機、序列埠或任何需要控制和序列化訪問的設備)時。
資料庫連接池: 單例模式可以管理資料庫連接池,確保有效重複使用連接並實現控制訪問。
(軟體)授權或配置檢查: 如果需要定期檢查軟體的授權或配置,單例可以確保檢查是集中化且一致的。
依照慣例,來舉一個例子吧~
假設今天一座城市裡只有1座機場,
機場裡雖然有好多不同的航空公司,
但一座城市裡只有一個機場,同時要確保所有航班的統一和安排
我們先來建一個機場單例
//singleton,確保整個城市只有一個機場實例
public class Airport
{
private static Airport instance;
private List<Flight> flights;
// 建立機場的private constructor
private Airport()
{
flights = new List<Flight>();
Console.WriteLine("機場已建立!");
}
// 獲取機場實例的方法,使用Singleton模式確保唯一性
public static Airport GetInstance()
{
if (instance == null)
{
instance = new Airport();
}
return instance;
}
// 添加航班到機場的航班列表
public void AddFlight(Flight flight)
{
flights.Add(flight);
Console.WriteLine($"新增航班 {flight.FlightNumber} 目的地:{flight.Destination}");
}
// 顯示所有已安排的航班
public void DisplayFlights()
{
Console.WriteLine("=== 航班列表 ===");
foreach (var flight in flights)
{
Console.WriteLine($"航班號:{flight.FlightNumber}, 目的地:{flight.Destination}");
}
Console.WriteLine("=================");
}
}
航班資料的class
// 航班類別
public class Flight
{
public string FlightNumber { get; set; }
public string Destination { get; set; }
public Flight(string flightNumber, string destination)
{
FlightNumber = flightNumber;
Destination = destination;
}
}
最後Main class,我們創建了一家機場實例,然後添加了兩個航班到機場的航班列表中,最後顯示了航班列表。
這確保了機場實例的唯一性,以及對所有航班的統一和安排,符合機場在城市中的唯一性的特性。
class Program
{
static void Main()
{
// 獲取機場實例
Airport airport = Airport.GetInstance();
// 創建一些航班
Flight flight1 = new Flight("FL123", "紐約");
Flight flight2 = new Flight("FL456", "洛杉磯");
// 添加航班到機場
airport.AddFlight(flight1);
airport.AddFlight(flight2);
// 顯示所有航班
airport.DisplayFlights();
Console.ReadLine();
}
}