享元模式就是运行共享技术有效地支持大量细粒度的对象,避免大量拥有相同内容的小类的开销,使大家共享一个类。
实现方式
- 将需要改写为享元的类成员变量拆分为两个部分:
- 内在状态:包含不变的、可在许多对象中重复使用的数据的成员变量
- 外在状态:包含每个对象各自不同的情景数据的成员变量
- 保留类中表示内在状态的成员变量,并将其属性设置为不可修改。这些变量仅可在构造函数中获得初始数值
找到所有使用外在状态成员变量的方法,为在方法中所用的每个成员变量新建一个参数,并使用该参数代替成员变量 ```typescript /**
- The Flyweight stores a common portion of the state (also called intrinsic
- state) that belongs to multiple real business entities. The Flyweight accepts
- the rest of the state (extrinsic state, unique for each entity) via its
method parameters. */ class Flyweight { private sharedState: any;
constructor(sharedState: any) { this.sharedState = sharedState; }
public operation(uniqueState): void { const s = JSON.stringify(this.sharedState); const u = JSON.stringify(uniqueState); console.log(
Flyweight: Displaying shared (${s}) and unique (${u}) state.); } }
4. 你可以有选择地创建工厂类来管理享元缓存池, 它负责在新建享元时检查已有的享元。 如果选择使用工厂, 客户端就只能通过工厂来请求享元, 它们需要将享元的内在状态作为参数传递给工厂```typescript/*** The Flyweight Factory creates and manages the Flyweight objects. It ensures* that flyweights are shared correctly. When the client requests a flyweight,* the factory either returns an existing instance or creates a new one, if it* doesn't exist yet.*/class FlyweightFactory {private flyweights: {[key: string]: Flyweight} = <any>{};constructor(initialFlyweights: string[][]) {for (const state of initialFlyweights) {this.flyweights[this.getKey(state)] = new Flyweight(state);}}/*** Returns a Flyweight's string hash for a given state.*/private getKey(state: string[]): string {return state.join('_');}/*** Returns an existing Flyweight with a given state or creates a new one.*/public getFlyweight(sharedState: string[]): Flyweight {const key = this.getKey(sharedState);if (!(key in this.flyweights)) {console.log('FlyweightFactory: Can\'t find a flyweight, creating new one.');this.flyweights[key] = new Flyweight(sharedState);} else {console.log('FlyweightFactory: Reusing existing flyweight.');}return this.flyweights[key];}public listFlyweights(): void {const count = Object.keys(this.flyweights).length;console.log(`\nFlyweightFactory: I have ${count} flyweights:`);for (const key in this.flyweights) {console.log(key);}}}
- 客户端必须存储和计算外在状态 (情景) 的数值, 因为只有这样才能调用享元对象的方法。 为了使用方便, 外在状态和引用享元的成员变量可以移动到单独的情景类中
```typescript
/**
- The client code usually creates a bunch of pre-populated flyweights in the
- initialization stage of the application. */ const factory = new FlyweightFactory([ [‘Chevrolet’, ‘Camaro2018’, ‘pink’], [‘Mercedes Benz’, ‘C300’, ‘black’], [‘Mercedes Benz’, ‘C500’, ‘red’], [‘BMW’, ‘M5’, ‘red’], [‘BMW’, ‘X6’, ‘white’], // … ]); factory.listFlyweights();
// …
function addCarToPoliceDatabase( ff: FlyweightFactory, plates: string, owner: string, brand: string, model: string, color: string, ) { console.log(‘\nClient: Adding a car to database.’); const flyweight = ff.getFlyweight([brand, model, color]);
// The client code either stores or calculates extrinsic state and passes it// to the flyweight's methods.flyweight.operation([plates, owner]);
}
addCarToPoliceDatabase(factory, ‘CL234IR’, ‘James Doe’, ‘BMW’, ‘M5’, ‘red’);
addCarToPoliceDatabase(factory, ‘CL234IR’, ‘James Doe’, ‘BMW’, ‘X1’, ‘red’);
factory.listFlyweights();
<a name="dIzSo"></a># 实际使用场景未使用享元时的代码:<br />创建了一万个实例,但是他们的某些字段数据都相同,造成内存浪费```typescriptclass Iphone11 {constructor(model: string, screen: number, memory: number, sn: number) { }}const phones = [];for (let i = 0; i < 10000; i++) {let memory = i % 2 == 0 ? 128 : 256;phones.push(new Iphone11("iPhone11", 6.1, memory, i));}
使用享元模式:
将大部分相同的数据抽离到享元类中:
/*** 内部状态:model, screen, memory* 外部状态:sn*/class IphoneFlyweight {constructor(model: string, screen: number, memory: number) {}}
定义一个对象来保存享元对象,并提供一个方法根据参数来获取享元对象
class FlyweightFactory {private phonesMap: { [s: string]: IphoneFlyweight } = {};public get(model: string, screen: number, memory: number): IphoneFlyweight {const key = model + screen + memory;if (!this.phonesMap[key]) {this.phonesMap[key] = new IphoneFlyweight(model, screen, memory);}return this.phonesMap[key];}}
定义 Iphone 类
class Iphone {constructor(flyweight: IphoneFlyweight, sn: number) { }}
定义 IphoneFactory 类
在型号、屏幕和内存相同的情况下,会共享由 IphoneFlyweight 享元类创建的享元对象。
class IphoneFactory {private static flyweightFactory: FlyweightFactory = new FlyweightFactory();public getIphone(model: string,screen: number,memory: number,sn: number) {const flyweight: IphoneFlyweight = IphoneFactory.flyweightFactory.get(model,screen,memory);return new Iphone(flyweight, sn);}}
function show(): void {const iphoneFactory = new IphoneFactory();const phones = [];for (let i = 0; i < 10000; i++) {let memory = i % 2 == 0 ? 128 : 256;phones.push(iphoneFactory.getIphone("iPhone11", 6.1, memory, i));}console.log("Already created 10000 iPhone11");}
