This Javascript program demonstrates a flyweight design pattern.
<!DOCTYPE html> <html> <head> <title>XoaX.net's Javascript</title> <script type="text/javascript" src="Flyweight.js"></script> </head> <body onload="Initialize()"> <canvas id="idCanvas" width="600" height ="600" style="background-color:#F0F0F0;border:1px lightblue solid;"></canvas> </body> </html>
function Initialize() {
const qCanvas = document.getElementById("idCanvas");
const qContext2D = qCanvas.getContext("2d");
let qFlyWeightFactory = new CFlyWeightFactory(qContext2D);
let qClient = new CClient(qFlyWeightFactory, qContext2D);
qClient.AddSquare(10, 20);
qClient.AddSquare(480, 60);
qClient.AddSquare(360, 450);
qClient.AddSquare(460, 300);
qClient.AddCircle(430, 170);
qClient.AddCircle(240, 180);
qClient.AddCircle(120, 340);
qClient.Draw();
}
class CClient {
#mqaFlyWeightIntrinsic;
#mqaSquareExtrinsic;
#mqaCircleExtrinsic;
constructor(qFlyWeightFactory) {
this.#mqaFlyWeightIntrinsic = [];
this.#mqaFlyWeightIntrinsic["square"] = qFlyWeightFactory.GetFlyWeight("square");
this.#mqaFlyWeightIntrinsic["circle"] = qFlyWeightFactory.GetFlyWeight("circle");
this.#mqaSquareExtrinsic = [];
this.#mqaCircleExtrinsic = [];
}
AddSquare(dX, dY) {
this.#mqaSquareExtrinsic.push({x:dX, y:dY});
}
AddCircle(dX, dY) {
this.#mqaCircleExtrinsic.push({x:dX, y:dY});
}
Draw(){
for (let i = 0; i < this.#mqaSquareExtrinsic.length; ++i) {
this.#mqaFlyWeightIntrinsic["square"].Draw(this.#mqaSquareExtrinsic[i]);
}
for (let i = 0; i < this.#mqaCircleExtrinsic.length; ++i) {
this.#mqaFlyWeightIntrinsic["circle"].Draw(this.#mqaCircleExtrinsic[i]);
}
}
}
class CFlyWeightFactory {
#mqaImages;
#mqContext;
constructor(qContext) {
this.#mqaImages = [];
this.#mqContext = qContext;
}
GetFlyWeight(sKey) {
if (!this.#mqaImages.includes(sKey)) {
switch(sKey) {
case "square":
let qSquareBitmapPromise = CreateSquare(this.#mqContext);
this.#mqaImages[sKey] = new CConcreteSquare(qSquareBitmapPromise, this.#mqContext);
break;
case "circle":
let qCircleBitmapPromise = CreateCircle(this.#mqContext);
this.#mqaImages[sKey] = new CConcreteCircle(qCircleBitmapPromise, this.#mqContext);
break;
default:
console.log("Error: Unknown key");
return null;
}
}
return this.#mqaImages[sKey];
}
}
function CreateCircle(qContext) {
let qImageData = qContext.createImageData(100, 100);
for (var i = 0; i < qImageData.data.length; i += 4) {
let x = (i % 400)/4 - 50;
let y = Math.floor(i/400) - 50;
let d = 49 - Math.sqrt(x*x + y*y);
// Between -1 and 1, do a partial fill
qImageData.data[i] = qImageData.data[i+1] = qImageData.data[i+2] = 128;
if (d > 1) {
qImageData.data[i+3] = 255; // Half transparency
} else if (d < -1){
qImageData.data[i+3] = 0; // Totally transparent
} else {
qImageData.data[i+3] = Math.floor(255*(d + 1)/2);
}
}
return createImageBitmap(qImageData);
}
function CreateSquare(qContext) {
let qImageData = qContext.createImageData(100, 100);
for (var i = 0; i < qImageData.data.length; i += 4) {
qImageData.data[i] = qImageData.data[i+1] = qImageData.data[i+2] = 200;
qImageData.data[i+3] = 255;
}
return createImageBitmap(qImageData);
}
class CAFlyWeight {
constructor() {
// This can be used to detect instantiation of the abstract class.
if (this.constructor === CAFlyWeight) {
throw new Error("Instantiated abstract class error: CAFlyWeight");
}
}
Draw(qExtrinsicState) {}
}
class CConcreteSquare extends CAFlyWeight {
#mqBitmapPromise;
#mqContext;
constructor(qBimapPromise, qContext) {
super();
this.#mqBitmapPromise = qBimapPromise;
this.#mqContext = qContext;
}
Draw(qExtrinsicState) {
// Wait for the promise to complete before rendering the image to the canvas
this.#mqBitmapPromise.then((qBitmapResult) => {
this.#mqContext.drawImage(qBitmapResult, qExtrinsicState.x, qExtrinsicState.y);
});
}
}
class CConcreteCircle extends CAFlyWeight {
#mqBitmapPromise;
#mqContext;
constructor(qBimapPromise, qContext) {
super();
this.#mqBitmapPromise = qBimapPromise;
this.#mqContext = qContext;
}
Draw(qExtrinsicState) {
// Wait for the promise to complete before rendering the image to the canvas
this.#mqBitmapPromise.then((qBitmapResult) => {
this.#mqContext.drawImage(qBitmapResult, qExtrinsicState.x, qExtrinsicState.y);
});
}
}© 20072026 XoaX.net LLC. All rights reserved.