JAVA SCRIPT设计模式是本人根据GOF的设计模式写的博客记录。使用JAVA SCRIPT语言来实现主体功能,所以不可能像C++,JAVA等面向对象语言一样严谨,大部分程序都附上了JAVA SCRIPT代码,代码只是实现了设计模式的主体功能,不代表全部的正确,特此声明。若读者需要了解设计模式目录、原则、设计变化方向,环境相关等信息请查看设计模式开篇。
一、UML类图
参与者:
1.1 Flyweight(Glyph)
- 描述一个接口,通过这个接口flyweight可以接受并作用于外部状态
1.2 ConcreteFlyweight(Character)
- 实现Flyweight接口,并为内部状态(如果有的话)增加存储空间。ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的;即,它必须独立于ConcreteFlyweight对象的场景。
1.2 UnsharedConcreteFlyweight(Row,Column)
- 并非所有的Flyweight子类都需要被共享。Flyweight接口使共享成为可能,但它并不强制共享。在Flyweight对象结构的某些层次,UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点(Row和Column就是这样)。
1.2 FlyweightFactory
- 创建并管理flyweight对象。
- 确保合理地共享flyweight。当用户请求一个flyweight时,FlyweightFactory对象提供
- 个已创建的实例或者创建一个(如果不存在的话)。
1.2 Client
- 维持一个对flyweight的引用。
- 计算或存储一个(多个)flyweight的外部状态。
二、意图
运用共享技术有效地支持大量细粒度的对象。
三、适用性
- 一个应用程序使用了大量的对象。
- 完全由于使用大量的对象,造成很大的存储开销。
- 对象的大多数状态都可变为外部状态。
- 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
- 应用程序不依赖于对象标识。由于Flyweight对象可以被共享,对于概念上明显有别的对 象,标识测试将返回真值。
四、示例代码
4.1 动机
Flyweight模式对那些通常因为数量太大而难以用对象来表示的概念或实体进行建模。例如,文档编辑器可以为字母表中的每一个字母创建一个flyweight。每个flyweight存储一个字符代码,但它在文档中的位置和排版风格可以在字符出现时由正文排版算法和使用的格式化命令决定。字符代码是内部状态,而其他的信息则是外部状态。
逻辑上,文档中的给定字符每次出现都有一个对象与其对应,如下图所示。
而这个对象出现在文档结构中的不同地方。 一个特定字符对象的每次出现都指向同一个实例,这个实例位于 flyweight对象的共享池中。
表示字母“a”的flyweight只存储相应的字符代码;它不需要存储字符的位置或字体。用户提供与场景相关的信息,根据此信息flyweight绘出它自己。例如,Rowglyph知道它的子女应该在哪儿绘制自己才能保证它们是横向排列的。因此Rowglyph可以在绘制请求中向每一个子女传递它的位置。
由于不同的字符对象数远小于文档中的字符数,因此,对象的总数远小于一个初次执行的程序所使用的对象数目。对于一个所有字符都使用同样的字体和颜色的文档而言,不管这个文档有多长,需要分配100个左右的字符对象(大约是ASCII字符集的数目)。由于大多数文档使用的字体颜色组合不超过10种,实际应用中这一数目不会明显增加。因此,对单个字符进行对象抽象是具有实际意义的
4.2 示例UML
目录结构:
4.2 Flyweight(Glyph)
- 描述一个接口,通过这个接口flyweight可以接受并作用于外部状态
export default class Glyph {
ctx;
constructor(ctx) {
this.ctx=ctx;
}
Draw(context) {
}
add(graphic)
{
}
}
4.3 ConcreteFlyweight(Character)
- 实现Flyweight接口,并为内部状态(如果有的话)增加存储空间。ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的;即,它必须独立于ConcreteFlyweight对象的场景。
import Glyph from '../Glyph.js';
export default class Character extends Glyph {
char ;
constructor(ctx) {
super(ctx );
}
Draw(context) {
console.log(` Character Draw `+this.char);
this.ctx.font=context.font;//"35px Arial";
this.ctx.fillText(this.char,context.x,context.y);
}
SetChar(char)
{
this.char=char;
}
}
4.4 UnsharedConcreteFlyweight(Row,Column)
- 并非所有的Flyweight子类都需要被共享。Flyweight接口使共享成为可能,但它并不强制共享。在Flyweight对象结构的某些层次,UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点(Row和Column就是这样)。
import Glyph from '../Glyph.js';
export default class Page extends Glyph {
rowchildrens = [];
constructor(ctx) {
super(ctx );
}
Draw(context) {
console.log(` Page Draw `);
for(let n=0;n<this.rowchildrens.length;n++)
{
let graphic=this.rowchildrens[n];
let height=this.GetRowHeight(n);//假设算法
context.y=height;
graphic.Draw(context);
}
}
AddRow(graphic) {
this.rowchildrens.push(graphic);
}
GetRowHeight(indexrow)
{
let height=0;
for(let n=0;n<=indexrow;n++)
{
let graphic=this.rowchildrens[n];
height=height+graphic.RowHeight;
}
return height;
}
}
import Glyph from '../Glyph.js';
export default class ROW extends Glyph {
childrens = [];
RowHeight=30;
constructor(ctx) {
super(ctx );
}
Draw(context) {
console.log(` ROW Draw `);
for(let n=0;n<this.childrens.length;n++)
{
let graphic=this.childrens[n];
context.x=n*30;//假设算法
graphic.Draw(context);
}
}
Add(graphic) {
this.childrens.push(graphic);
}
}
4.5 FlyweightFactory
- 创建并管理flyweight对象。
- 确保合理地共享flyweight。当用户请求一个flyweight时,FlyweightFactory对象提供
- 个已创建的实例或者创建一个(如果不存在的话)。
import Character from './Glyph/impl/Character.js';
export default class FlyweightFactory {
charpool= new Map();
ctx;
constructor(ctx) {
this.ctx=ctx;
}
GetFlyweight(key) {
if(this.charpool.has(key))
return this.charpool.get(key);
else{
let onechar=new Character(this.ctx);
onechar.SetChar(key);
this.charpool.set(key,onechar);
return onechar;
}
}
}
4.6 Client
- 维持一个对flyweight的引用。
- 计算或存储一个(多个)flyweight的外部状态。
import FlyweightFactory from './FlyweightFactory.js';
import Glyph from './Glyph/Glyph.js';
import Character from './Glyph/impl/Character.js';
import Page from './Glyph/impl/Page.js';
import ROW from './Glyph/impl/ROW.js';
import Contenxt from './Context.js';
export default class Client{
main(ctx){
let flyweight =new FlyweightFactory(ctx);
let achar =flyweight.GetFlyweight('a');//Glyph
let bchar =flyweight.GetFlyweight('b');//Glyph
let cchar =flyweight.GetFlyweight('c');//Glyph
let row1=new ROW(ctx);
row1.Add(achar);
row1.Add(bchar);
let row2=new ROW(ctx);
row2.Add(achar);
row2.Add(cchar);
let page=new Page(ctx);
page.AddRow(row1);
page.AddRow(row2);
let contentx=new Contenxt("35px Arial",0,0,300,300);
page.Draw(contentx);
}
}
4.7 测试HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="module" >
import Client from './Client.js';
var x=document.getElementById("mycanvas")
var ctx=x.getContext("2d") //create 2d object
let cl=new Client();
cl.main(ctx)
</script>
</head>
<body>
<canvas id="mycanvas" width=300px height=300px></canvas>
</body>
</html>
测试结果:
Page.js:10 Page Draw
ROW.js:10 ROW Draw
Character.js:9 Character Draw a
Character.js:9 Character Draw b
ROW.js:10 ROW Draw
Character.js:9 Character Draw a
Character.js:9 Character Draw c
五、源代码下载
下载链接:https://pan.baidu.com/s/1XuPqp84cccBNVkbnMY3sKw
提取码:q2ut