ArkTS建造者模式
建造者模式的优点在于伸缩性强+线程安全,在复杂bean的初始化中经常使用,下面是一个Effective Java书中的例子
// Builder Pattern
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder {
// Required parameters
private final int servingSize;
private final int servings;
// Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val) {
calories = val;
return this;
}
public Builder fat(int val) {
fat = val;
return this;
}
public Builder sodium(int val) {
sodium = val;
return this;
}
public Builder carbohydrate(int val) {
carbohydrate = val;
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
实现的关键是Bean只能由Builder初始化,所以Bean的构造函数私有化,保证外界不能new,但Builder作为静态内部类任然可以访问
ArkTS没有静态内部类,想实现上面的效果可以在Bean的构造函数中增加一个只能由Builder创建的token,下面是对应的例子
// 1. 定义私有令牌类(仅在模块内可见)
class ConstructionToken {
// 私有构造函数确保只有本模块能创建实例
private constructor() {
}
// 工厂方法只允许 Builder 访问
static create(): ConstructionToken {
return new ConstructionToken();
}
}
// 2. NutritionFacts产品类
export class NutritionFacts {
private _servingSize: number;
public get servingSize(): number {
return this._servingSize;
}
private _servings: number;
public get servings(): number {
return this._servings;
}
private _calories?: number;
public get calories(): number | undefined {
return this._calories;
}
private _fat?: number;
public get fat(): number | undefined {
return this._fat;
}
private _sodium?: number;
public get sodium(): number | undefined {
return this._sodium;
}
private _carbohydrate?: number;
public get carbohydrate(): number | undefined {
return this._carbohydrate;
}
/**
* 公开构造函数,但必须提供令牌
* @param token
* @param servingSize
* @param servings
* @param calories
* @param fat
* @param sodium
* @param carbohydrate
*/
constructor(
token: ConstructionToken, // 必须提供令牌
servingSize: number,
servings: number,
calories?: number,
fat?: number,
sodium?: number,
carbohydrate?: number,
) {
// 验证令牌有效性
if (!(token instanceof ConstructionToken)) {
throw new Error("Invalid construction token");
}
this._servingSize = servingSize
this._servings = servings
this._calories = calories
this._fat = fat
this._sodium = sodium
this._carbohydrate = carbohydrate
}
}
// 3. NutritionFacts建造者
export class NutritionFactsBuilder {
private _servingSize: number;
private _servings: number;
private _calories?: number;
private _fat?: number;
private _sodium?: number;
private _carbohydrate?: number;
setServingSize(servingSize: number): NutritionFactsBuilder {
this._servingSize = servingSize;
return this;
}
setServings(servings: number): NutritionFactsBuilder {
this._servings = servings;
return this;
}
setCalories(calories: number): NutritionFactsBuilder {
this._calories = calories;
return this;
}
setFat(fat: number): NutritionFactsBuilder {
this._fat = fat;
return this;
}
setSodium(sodium: number): NutritionFactsBuilder {
this._sodium = sodium;
return this;
}
setCarbohydrate(carbohydrate: number): NutritionFactsBuilder {
this._carbohydrate = carbohydrate;
return this;
}
build(): NutritionFacts {
if (!this._servingSize || !this._servings) {
throw new Error("servingSize和servings是必须参数");
}
// 获取有效构建令牌
const token = ConstructionToken.create();
return new NutritionFacts(
token,
this._servingSize,
this._servings,
this._calories,
this._fat,
this._sodium,
this._carbohydrate
);
}
}