文章目錄
- 前言
- 一、構造函數是什么?
- 二、構造函數的用法
- 1.初始化對象,避免無效狀態
- 2 初始化靜態成員
- 3 構造函數重載
- 4.構造函數鏈
- 5. 單例模式,多次實例化保持一個對象
- 6. 依賴注入
- 7. 初始化只讀對象
前言
構造函數是我們平常編程里經常能碰到的老伙計了,構造函數本質上是類中一種特殊的成員方法,用于在實例化對象的時候,對該類中的一些狀態進行初始化。本篇文章總結下工作中經常能碰到的使用構成函數的場景,希望能幫助到大家。
一、構造函數是什么?
構造函數可以理解成一個特殊的方法,當一個類被實例化時,這個構造函數會被自動調用,用作初始化這個對象。但是,構造函數的功能根據應用場景,可以擴展為不同的用法。
二、構造函數的用法
1.初始化對象,避免無效狀態
很多時候初始化對象,需要給對象設定一種狀態,我哪一種業務邏輯舉例。賣出去的商品價格不能為負數,庫存數量也不能小于零。
這里構造函數最的作用是保證商品對象在創建時就處于有效狀態,避免因價格設置錯誤,庫存數量設置錯誤導致后續邏輯出錯,作為一個業務邏輯的檢驗之用。
internal class Product
{public string productId { get; }/// <summary>/// 價格 > 0/// </summary>public double price { get; }/// <summary>/// 庫存 > 0/// </summary>public int stock { get; }// 構造函數:初始化+參數校驗public Product(String productId, double price, int stock){this.productId = productId;// 校驗價格合法性,非法則拋出異常,阻止對象創建if (price < 0){throw new ArgumentOutOfRangeException("商品價格不能為負數:" + price);}this.price = price;// 校驗庫存合法性if (stock < 0){throw new ArgumentOutOfRangeException("商品庫存不能為負數:" + stock);}this.stock = stock;}
}
2 初始化靜態成員
靜態變量,靜態屬性這類成員屬于類本身,而非類的實例。它的初始化方式就是通過構造函數初始化的。確保了靜態成員在類的整個生命周期中保持一致的初始狀態,適合存儲全局共享的數據。
比方說一個日志類需要一個屬性存放文件目錄,用靜態屬性的方式就很合適,使用構造函數初始化靜態成員。
internal class log
{public static string PhyPath { get; private set; }static log(){PhyPath = AppDomain.CurrentDomain.BaseDirectory;}
}
3 構造函數重載
構造函數重載允許一個類定義多個構造函數,這些構造函數具有相同的名稱但參數不同,包括不限于參數個數,參數類型,參數順序。這是一種靈活的初始化方式,從而應對實例化的時候的各種場景。
這里提供兩種構造函數,一個參數是包含電影名稱和描述信息,另一個構造函數只包含電影名稱,這樣實例化Movie類的時候,就能通過兩種方式實例化Movie。為對象提供多種初始化方式,滿足不同場景的需求
internal class Movie
{public int Id { get; set; }public string MovieName { get; set; }public string Desc { get; set; }public Movie(string MovieName){this.MovieName = MovieName;this.Desc = "";}public Movie(string MovieName,string Desc){this.MovieName = MovieName;this.Desc = Desc;}}
4.構造函數鏈
子類繼承父類的時候,子類可以通過base關鍵字調用父類的構造函數,實現子類向父類傳遞參數的情況,也能避免重復代碼。
比方說我有一個父類,提供一個構造函數,子類可以通過調用父類的構造函數實現狀態的配置化。
/// 父類
public BaseClass(String HttpMethod)
{if (HttpMethod.ToUpper() == "GET"){_httpRequest = HttpContext.Current.Request.QueryString;}if (HttpMethod.ToUpper() == "POST"){_httpRequest = HttpContext.Current.Request.Form;}
}/// 子類
public ChiledClass() : base(HttpContext.Current.Request.HttpMethod)
{
}
5. 單例模式,多次實例化保持一個對象
在數據操作這類服務,經常是能碰到使用單例模式的場景。多次實例化一個數據服務對象,返回的任然是同一個實例,禁止外部直接創建對象。這樣既能保證資源利用的最大化,并且類能自主控制創建規則,保證代碼安全性。
比方說初始化一個RedisServer服務,其構造函數是私有的,無法直接通過初始化的時候執行這個構造函數。通過Lazy這延遲初始化工具,確保RedisServer實例在首次被使用時通過調用內部私有的構造函數創建,實現 “懶加載”。最后通過一個靜態實例返回lazy.Value 實現單例模式
/// <summary>
/// Redis單例服務
/// </summary>
public sealed class RedisServer
{//私有靜態字段,存儲唯一實例private static readonly Lazy<RedisServer> lazy = new Lazy<RedisServer>(() => new RedisServer());/// <summary>/// 靜態實例/// </summary>public static RedisServer Instance { get { return lazy.Value; } }/// <summary>/// Redis連接對象/// </summary>private readonly ConnectionMultiplexer _redis;/// <summary>/// Redis數據庫對象/// </summary>private readonly IDatabase _db;/// <summary>/// Redis單例服務/// </summary>private RedisServer(){/// 邏輯:/// 1. 創建Redis連接對象/// 2. 創建Redis數據庫對象}/// <summary>/// 獲取Redis數據庫對象/// </summary>public IDatabase GetDatabase(){return _db;}
}
6. 依賴注入
依賴注入中,也可以是通過構造函數來實現接收依賴項的。另外就是這里通過構造函數初始化只讀屬性,這樣可以創建不可變對象,實現線程安全。
[Route("api/[controller]/[action]")]
[ApiController]
public class AuthController : ControllerBase
{private readonly ILogger<AuthController> _logger;private readonly IJWTService _jwtService;public AuthController(ILogger<AuthController> logger = null, IJWTService jwtService = null){_logger = logger;_jwtService = jwtService;}[HttpGet]public ActionResult<string> test(){return "test";}[HttpPost]public ActionResult<string> Login([FromBody]LoginUser loginUser) { var token = _jwtService.GenerateToken(new CurrentUser() { UserId = loginUser.UserId,Name = "張三",Age = 18,NickName = "張三", RoleList = new List<string>() { "admin" } });return token;}
}
7. 初始化只讀對象
只能在構造函數中初始化readonly字段,創建不可變對象,實現線程安全。
代碼如上。