程序中經常會用到很多不同的設計模式, 而工廠模式的使用率, 是設計模式中使用率比較高的.
當我們用工廠模式的時候, 需要寫一個Factory來創建各個類
interface IObjConstructor {
new <T>() : T;
}
function create(c : IObjConstructor) : C1 {
return new c()
}
代碼里的create就是我們要的factory了, 然后我們寫一個class實現IObjConstructor接口.
class C1 implements IObjConstructor {
constructor() {
}
}
這段代碼看上去很正常, C1類實現了接口IObjConstructor, 但是編譯會報錯
Type 'C1' provides no match for the signature 'new <T>(): T'
奇怪了, 為什么說C1沒有這個new屬性呢? 我們看看官方文檔關于interface的說法:
This is because when a class implements an interface, only the instance side of the class is checked. Since the constructor sits in the static side, it is not included in this check.
意思就是當class實現一個接口的時候, 只會檢查實例面, 靜態面是不檢查的, 所以說找不到.
那么, 哪些是靜態部分, 哪些是實例部分呢? 我們寫一段ts,
class C1 {
static s1: number = 5
public s2: number = 0
constructor() {
}
}
把代碼編譯成js
var C1 = (function () {
function C1() {
this.s2 = 0; //實例面
}
C1.s1 = 5; //靜態面
return C1;
}());
這里可以看出來, 因為ts里面的class, 其實編譯成js, 還是一個function, 而且是function里面的function, 那么外function就是靜態面, 內function就是實例面, 內function當然沒有new.
注意, 只有當class實現一個接口的時候, 才是檢查實例面, 當類型以參數傳入時, 是檢查靜態面的, 例如
interface IObjConstructor {
new <T>() : T;
add(a1:number, a2:number) : number
}
class C1 {
constructor() {
}
add(a1:number, a2:number) : number {
return a1 + a2
}
}
function create(c : IObjConstructor) : C1 {
return new c()
}
這段代碼會得到一個錯誤
Property 'add' is missing in type 'typeof C1'.
那么, 我們要同時約束類的構造函數和其它的屬性函數, 要怎么做呢?
要解決這個問題, 我們用create函數約束構造函數, 用接口約束其它屬性函數, 例如:
interface IObjConstructor {
new <T>() : T;
}
interface IObjAction{
add(a1:number, a2:number) : number;
}
class C1 implements IObjAction {
constructor() {
}
add(a1:number, a2:number) : number {
return a1 + a2
}
}
function create<T extends IObjAction>(c : IObjConstructor) : T{
return new c<T>()
}
const c1 = create(C1)
console.log(c1.add(4, 5)) // = 9
這里IObjConstructor 約束構造函數, new用了泛型, 根據調用的類型T生成一個類型T的實例, C1實現IObjAction, 約束其它的函數.
由于C1傳入到create, 并不會自動識別為IObjAction , 所以create函數的泛型類型T繼承IObjAction, 讓new最終生成的類型屬于IObjAction, .
到這里已經用typescript實現了工廠模式.