flyweight pattern 又称享元模式
Use sharing to support large numbers of fine-grained objects efficiently --- GoF
运用共享技术有效地支持大量细粒度的对象
UnshareConcreteFlyweight:并不是所有的Flyweight具体实现子类都需要被共享的,如果是不能共享的,那么就只能是它只能被引用一个。ConcreteFlyweight:可以被共享,该对象可以被多个引用。还是以汽车模型为例子,例如我们来建立一个跑车的部分场景,每个赛车都有轮胎,外壳,品牌,引擎这个部分组成,轮胎影响飘逸和刹车的效果,外壳仅仅是外观效果,引擎影响最大速度和加速度,品牌影响可以被撞后影响。我们游戏会有40辆车,如果构建这20辆车需要160个对象,但是我们发现这160个对象太消耗系统性能与资源了,其实有些对象是一样的的,那么在这个场景中,完全可以共享这些对象,那么这样可以节省好多对象的构造与析构,系统牺牲一定空间来提升性能与效率。轮胎有:米其林,普利司通两种轮胎Michelin轮胎:摩擦系数很高,漂移效果好,损耗很高Bridgestone轮胎:摩擦细数一般,漂移效果一般,损耗一般外壳有:红色,黑色,白色,蓝色,绿色,黄色,紫色七种品牌有:宝马,法拉利,奥迪,奔驰四种BMW:坚固性强,被撞减速一般Ferrari: 坚固性弱,被减速大Audi:坚固性一般,被减速大Benz:坚固性一般,被减速小引擎:法拉利研制,红牛研制,奔驰研制,宝马研制Ferrari:速度高,加速高Redbull:速度高,加速一般Benz:速度一般,加速一般BMW:速度一般,加速快
模拟从数据库或者配置表里获得数据function.h文件
#include <iostream> float getFriction(std::string wheelname); float getDrifting(std::string wheelname); float getPorperty(std::string wheelname); int getPamer(std::string brandname); float getEffect(std::string brandname); int getMaxSpeed(std::string makename); int getAcceleration(std::string makename);
function.cpp文件
#include "function.h" float getFriction(std::string wheelname) { if(wheelname=="Michelin")return 240; else if(wheelname=="Bridgestone")return 200; else return -1; } float getDrifting(std::string wheelname) { if(wheelname=="Michelin")return 100; else if(wheelname=="Bridgestone")return 80; else return -1; } float getPorperty(std::string wheelname) { if(wheelname=="Michelin")return 0.03; else if(wheelname=="Bridgestone")return 0.02; else return -1; } int getPamer(std::string brandname) { if(brandname=="BMW") return 3;
前面通过脚本获取数据源,以及在报表中利用单元格或者数据项的onRender方法添加脚本来增加交互性,或者直接在脚本编辑器中书写少量代码,或多或少的都利用到了BIRT的脚本和事件机制,但这仅仅只是冰山一角。
BIRT提供了一个基于Mozilla Rhino的脚本模型。报表引擎创建报表的过程可以划分为两个阶段——生成和呈现。生成阶段利用报表设计,生成一个名为报表文档的中间文件。呈现阶段利用报表文档进行渲染,生成HTML或PDF。报表生产线既可以将两个阶段作为一个任务执行,也可以作为两个任务分别执行。如果作为一个任务,那么报表文档是生成在内存中。在设计器中选择『以HTML方式预览』时,默认是采用这种方式的。反之,如果作为两个任务分别执行,那么报表文档将被保存在磁盘中。在设计器中选择『在浏览器中预览』时,默认是采用这种方式的。
每一个阶段的事件都通过事件处理器覆盖,用以修改报表内容。既可以用JavaScript,也可以用Java。
事件:
三大对象——报表对象、报表元素和数据源(集)——具有脚本事件。当前所处的阶段决定了可以定制的事件类型和对象属性。
下图描绘了包含一个表和一个数据元素的简单报表的事件触发顺序:
产生阶段:
展现阶段:
我们以一个报表为例来打印出事件的执行顺序:
我们新建报表javascript_logging_demo.rptdesign,选用脚本数据源,定义数据集,
仅仅只有两列
row_int 整数
row_string 字符串
我们在获取数据集的时候必须书写两个方法:
open方法
rowCount = 0;
fetch方法:
while (rowCount < 5) {
rowCount ++;
row['row_int'] = rowCount;
row['row_string'] = "another string " + rowCount;
return true;
}
把两个数据列拖入一个1行2列的表中,布局报表报表,做适当美化,预览效果如下:
为了查看这个报表的事件执行顺序,我们需要在报表,数据源,数据集,表,行,数据项上书写一系列日志,方法如下:
选择大纲视图,选择报表编辑器的脚本查看选项卡:
我们选中报表名称,在initialize中书写如下的语句:
// INTIALIZE THE LOGGER WITH A FILE BASED LOGGER importPackage(Packages.java.util.logging); importPackage(Packages.logging); var fileHandler = new FileHandler("javascript.log", false); //fileHandler.setFormatter(new BirtEventFormatter()); var rootLogger = Logger.getLogger(""); rootLogger.addHandler(fileHandler); function log ( str ){ Logger.getAnonymousLogger().info(str); } reportContext.setPersistentGlobalVariable("log", log); log("Initialize");
说明:源码的含义是生成一个javascript.log文件,用来记录日志信息,并把写日志事件设置成全局常量方法,以便在其他方法中直接调用。
这样,我们在选中数据源,数据集,表,行,单元格,数据项时,即可通过下拉方法框书写一系列日志。
例如在数据源上:
beforeOpen
log("Data Source Before Open");
Open
log("Data Source Open");
beforeClose
log("Data Source Before Close");
close
log("Data Source Close");
afterClose
log("Data Source After Close");
在数据集上
beforeOpen
log("Data Set Before Open");
Open
log("Data Set Open");
fetch
log("Data Set Fetch");
onFetch
log("Data Set OnFetch");
beforeClose
log("Data Set Before Close");
close
log("Data Set Close");
afterClose
log("Data Set After Close");
其它事件类似,不一一举例。
运行报表,我们在eclipse的根目录下可以看到产生的javascript文件:
内容如下:
<?xml version="1.0" encoding="GBK" standalone="no"?> <!DOCTYPE log SYSTEM "logger.dtd"> <log> <record> <date>2013-01-05T10:43:00</date> <millis>1357353780241</millis> <sequence>170</sequence> <level>INFO</level> <class>sun.reflect.NativeMethodAccessorImpl</class> <method>invoke0</method> <thread>12</thread> <message>Initialize</message> </record> <record> <date>2013-01-05T10:43:00</date> <millis>1357353780241</millis> <sequence>171</sequence> <level>INFO</level> <class>sun.reflect.NativeMethodAccessorImpl</class> <method>invoke0</me
上一篇博文我们说到了qml组件下拉列表的实现,但只能支持单选功能。在这篇文章,我将会讲一下本人下拉列表复选功能的实现方法(不代表是好方法,仅供参考)。
首先,在点击和鼠标划过等高亮效果方面,依然是自定义的;每个item被选中将会有高亮。然后和单选下拉列表不一样,点击选中时并没有立即收回。
同时,定义了一个数组,数组元素的值为0和1(其意义如代码中注释所示);在触发Click事件时,将会改变这些元素的值。在外部获取选中的item时,直接从这个数组的元素的值可获知。这肯定不是很好的方法,但是绝对简单了。
qml代码如下:
// import QtQuick 1.0 // to target S60 5th Edition or Maemo 5
import QtQuick 1.1
Rectangle {
id:comboBox
property variant daysOfWeekFlag:[0,0,0,0,0,0,0] // 1代表当日选中,0代表当日未选中
property variant items: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
signal comboClicked;
width: 110;
height: 30;
smooth:true;
onDaysOfWeekFlagChanged: {
chosenItemText.text = "";
for(var i=0; i<daysOfWeekFlag.length; ++i)
{
if(daysOfWeekFlag[i] !== 0)
{
chosenItemText.text += items[i];
chosenItemText.text += " ";
}
}
if(chosenItemText.text == "")
chosenItemText.text = "点击可选择"
}
Rectangle {
id:chosenItem
radius:4;
width:chosenItemText.width > parent.width?chosenItemText.width:parent.width
height:comboBox.height;
color: "#2EB3FF"
smooth:true;
Text {