JavaExplore

一切像雾像雨又像风
posts - 19, comments - 45, trackbacks - 0, articles - 0

2006年8月26日

     摘要: 3 数据源处理 JFreeChart 中的数据源是DataSet接口类型。该接口有三个主要的子类接口:CategoryDataset、PieDataset、SeriesDataset CategoryDataset 接口的实现类基本上都维护了一...  阅读全文

posted @ 2006-09-12 23:36 JavaExplore 阅读(6533) | 评论 (15)编辑 收藏

1、策略:常用于算法族,将算法从依赖的环境中抽象出来形成
2、状态:和策略非常接近,使用于有明显状态变化的时候
3、命令:命令的发起与执行解藕,命令类可以独立演化,有助于做redo undo操作以及记录所执行的命令
4、解释:用于文法的解析
5、迭代子:java中有现成的实现,iterator
6、观察者:常见,类似与模型视图的关系,java中提供了oberver类和observable接口
7、调停者:处理混乱的类交互,抽象出中间类,将类间的交互都通过这个类完成
8、模版:将拥有同一父类的多个具体子类的共同操作提取出来形成抽象模版类
         原则:具体的私有属性应该放到具体类中,抽象类中调用属性通过属性方法而不是直接调用属性
               将私有属性放到具体的类中,才能方便对父类进行多个实现。
         将行为看作划分类的标准,以前我都是将数据模型看作划分类的思想,以后应该重新审视行为在类中的重要作用,特别是在的继承等级中。

posted @ 2006-09-12 23:33 JavaExplore 阅读(372) | 评论 (0)编辑 收藏

1 简介

JFreeChart SourceForge.net 上的一个开源项目,它的源码和 API 都可以免费获得。 JFreeChart 的功能非常强大,可以实现饼图 ( 二维和三维 ) ,  柱状图  ( 水平 , 垂直 ), 线图 , 点图 , 时序图 , 甘特图 股票行情图 , 混和图 温度计图 刻度图等常用商用图表,   图形可以导出成 PNG JPEG 格式,同时还可以与 PDF EXCEL 关联,支持对图形的放大、缩小,支持常见图形的 3D 显示。

2 图形 对象的处理

2 1 JFreeChart对象

JFreeChart 可以生成很多图形对象,它的工厂类提供了 33 个工厂方法用于生成不同的图形对象(具体的工厂方法可以参见 JFreeChart API 手册或者源码中的 ChartFactory )。              JFreechart 对图形对象的抽象具体化。图形对象( JFreeChart ),由 Title( 主标题 ) SubTitle (子标题 ) Plot (图形的绘制结构)等几个主要对象组成。各个组成部分如下图所示:

这是一个 JFreeChart 对象,上面的“ chart 标题”是 Title 对象,中间区域是 Plot 对象(包括绘图区域和坐标轴区域),下面的区域是 LegendTitle 对象,是一种 SubTitle 对象。

每个 JFreeChart 对象只能有 1 Title 对象, 1 Plot 对象,可以有多个 SubTitle 对象。 JFreeChart 对象可以进行的操作有:背景的设置(背景颜色、背景图片、透明度等)、边框的设置(是否可见、笔画、 Paint 等)、渲染方式的设置、标题对象的设置、子标题对象的增删查操作。(本文中的所有操作都不提供代码级的介绍,可参见 API 手册或者源码)

2 2 主标题对象

主标题对象是 TextTitle 类型,可以进行的操作有:背景设置、字体设置(字体类型、颜色、内容、对齐方式等操作)、 tooltip 设置、 URL 设置。

2 3 Plot 对象

Plot 对象是图形的绘制结构对象。 JFreeChart 中含有很多不同的 Plot 对象,每一种图形对象中的 Plot 对象都在实例化的时候创建。所有的 Plot 共有的操作有:背景设置(背景颜色、背景图片、透明度等)、前景透明度设置、无数据存在情况的设置(显示的字符内容、显示的字体、显示的 Paint )、放大缩小比例的设置,大部分 Plot 对象还有设置 Datset 、设置 Renderer 对象操作。

JFreeChart 中有 18 Plot 抽象类的具体实现类。 Plot 的具体实现类主要由以下重要对象组成: Renderer 对象(图形的绘制单元——绘图域) Datset (图形的数据源), DomainAxis (区域轴,相当于 x 轴), RangeAxis (范围轴,相当于 y 轴)。不同的 Plot 对象组成方式不尽相同,有的不含有 Renderer 对象,比如 CompassPlot ContourPlot MultiplePiePlot PiePlot 等,有的不含有 DomainAxis RangeAxis 对象,另外除了 FastScatterPlot 类都含有 Datset 对象, FastScatterPlot 使用 float 的二维数组充当数据源。尤其说明一点,饼状图相关的 Plot 对象( MultiplePiePlot PiePlot PiePlot3D RingPlot )中都不含有 Renderer 对象、 DomainAxis 对象、 RangeAxis 对象。

一般来说, Datset 对象存储数据模型, Renderer 对象存储显示模型, Plot 对象根据 Datset 对象、 Renderer 对象完成画图操作。

仍以上面的图形讲解 Plot 对象的组成。

   上图的中间区域是是一个 XYPlot 对象。其中的折线部分即是图形的绘制单元 Renderer 对象。 X 轴是 DomainAxis y 轴是 RangeAxis ,其中 Datset 对象属于数据模型范畴,是 UI 不可见对象。该图中的 plot 背景色、网格线的各种设置可以通过 XYPlot 对象本身完成。

       下面讲解 Renderer 对象、 Axis 对象( X 轴、 y 轴都属于 Axis 对象), Datset 对象在后续章节中专门讲解。

2 31 Renderer对象

Renderer 对象是图形的绘制单元。 JFreeChart 提供了两个接口 CategoryItemRenderer XYItemRenderer 1 个抽象类 AbstractRenderer 供具体的 Renderer 类实现,给出了将近 50 种具体实现类。

一般来说 Renderer 对象可进行的操作有:对 item label (下图中的柱状图上的红色数字即为 item label 的示例)的默认设置( item label 的产生方式、是否可见、字体、 Paint 、正反向 item label 的位置设置等)、绘制图形的边框默认设置( Paint 、笔画、是否可见等)、绘制图形的默认设置(形状、笔画、是否可见、对应的图例中是否可见等,折线图还有线条是否可见、折点图形是否可见、折点图形是否填充、折点图形的形状、对应的图例中线条是否可见、图形是否可见、整体是否可见等)、以及对指定 item label 的设置、指定绘制图形的设置。可以说和具体绘制的图形相关的属性都可以通过 Renderer 对象设置。

不同的 Renderer 的实现类实现了不同的显示方式,在含有 Renderer 对象的 JFreeChart 对象中, R enderer 对象决定了JFreeChart对象的显示方式。例如:柱状图的Plot对象中默认的Renderer对象是 CategoryItemRenderer 对象,通过设置 Plot 对象的Renderer对象 LineAndShapeRenderer ,则柱状图变为线图。使用中一般不需要显式的实例化一个 R enderer 对象,一般通过 JFreeChart 对象的 Plot 对象调用现有的 R enderer 对象进行重新设置等操作。

2 32 Axis对象

JFreeChart 提供了两种类型的坐标轴: CategoryAxis (等级轴)和 ValueAxis (值轴), ValueAxis 又有 3 个子类: DateAxis (时间轴)、 NumberAxis (数字轴)、 PeriodAxis (时期轴)。这些坐标轴还有更详细的子类,不再一一列举

Axis 对象可进行的操作有:标题的设置(内容、字体、Paint、显示角度等)、坐标线的设置(笔画、Paint、是否可见等)、刻度线的设置(是否可见、笔画、Paint、位于绘图区域的长度、位于绘图区域外的长度等)、刻度标示的设置(笔画、Paint、字体、与轴的距离等)、坐标轴范围设置等。

CategoryAxis 对象还可以进行的操作有: 刻度标示间距 设置( 最小间距、最大间距、指定间距)等。

ValueAxis 对象可进行的操作有:轴端设置(显示的图形形状)、范围设置(是否自动产生范围、自动产生的最小范围、最大范围、指定确定范围、指定范围大小等)、间隔设置(是否自动产生间隔、指定间隔)等。

DateAxis 对象还有对时间刻度显示格式的设置操作。

2 4 子标题对象

    子标题对象是 Title 类型的对象,一个JFreeChart可以有多个子标题对象。JFreeChart提供了5Title的实现,可以是图片、文本、图例等的形式。

(数据源以及常用图形的处理以及进一步的讨论在后续文章中介绍)
 

posted @ 2006-09-01 23:21 JavaExplore 阅读(9937) | 评论 (1)编辑 收藏

1、代理模式:参与角色:代理与真实实体共同的抽象角色、代理角色、真实实体角色
       远程代理:封装对与远程对象复杂的调用通讯过程,象调用本地对象一样
       虚拟代理:真实实体加载时间过长的,使用虚拟代理提供友好的显示方式,一边加载实际的对象
       安全代理:调用真实的对象之前插入权限验证模块
       智能引用代理:调用真实的对象之后调用统计等相关操作模块

2、享元模式:参与对象:建造工厂、抽象享元、具体享元
       分析对象的内蕴与外蕴状态,即不变的私有属性与变化的私有属性。建造工厂使用备忘录模式存储已经建造的对象,建造对象的时候,以参数的形式传递享元对象的内蕴属性。实际调用中,使用传递外部参数的方法使用外蕴变量。

   复合的享元对象组成的对象,不可以整体使用享元模式,但可以单个的享元对象属性使用该模式
   优点:降低内存中的对象  缺点:设计复杂性
       

3、门面模式:结构模式。为包含有很多对象的子系统提供统一的操作接口类,所有对该子系统的调用都通过这个类,降低子系统之间调用的复杂度,也符合笛比特法则(一个对象的朋友尽量少,只与朋友说话)

4、桥梁模式:参与角色:抽象化角色、抽象化的具体角色、实现化角色、实现化的具体角色
 两个有继承等级的对象群,一个对象群对另一个对象群有调用关系的时候使用
        目的:使抽象化与实现化解藕

posted @ 2006-09-01 23:08 JavaExplore 阅读(721) | 评论 (0)编辑 收藏

         今天去jdon,看了它的设计研究栏目,bang有几篇评论单例模式的文章,声称“Singleton is evil”(见http://www.jdon.com/jive/article.jsp?forum=91&thread=17578),并且引用几篇外文页面佐证自己的观点,其中有一篇文章更是说,单例不仅不是一种模式,而是一种反模式。
        下面我谈谈我对单例模式的看法。逐一分析单例模式的陷阱,帮助大家正确使用单例模式。
(1) 陷阱一:调用函数的性能瓶颈
        在c++中,单例只有一种实现方式——LazySingleton, 实现如下(本文全部使用java代码):

public   class  LazySingleton {
    
private   static  LazySingleton m_instance = null ;
     private LazySingleton(){};
     synchronized public static LazySingleton getInstance(){
        
if(m_instance==null)
            m_instance
=new LazySingleton();
        
return m_instance;
    }

}

LazySingleton将对象的初始化推迟到调用的时候。并且为了防止多线程环境下产生多个实例,使用synchronized关键字保证函数getInstance调用的线程安全。synchronized关键字的存在保证了只会产生一个对象,但也成了多线程环境下的性能瓶颈。一个多线程的程序,到了这里却要排队等候成了一个单线程式的执行流程,这在高并发环境下是不可容忍的。而c++中可以使用双重检查机制将这种性能问题仅仅限制在第一次构造对象的时候,而java中不可以使用双重检查机制。
        但是java可以实现EagerSingleton,实现如下:

public   class  EagerSingleton {
    
private   static  EagerSingleton m_instance = new  EagerSingleton();
     private EagerSingleton(){};
     public static agerSingleton getInstance(){
        
return m_instance;
    }

}
与LazySingleton相比,EagerSingleton将对象的初始化放到了类加载的时候。这样就避免了synchronized关键字的性能瓶颈。
(2)陷阱二:访问互斥共享资源
         EagerSingleton中访问互斥资源也要考虑线程安全问题。下面看一个例子:
public class EagerSingleton{
    
private static EagerSingleton m_instance=new EagerSingleton();
    
private HashMap map=new HashMap();
   
private EagerSingleton(){};
   
public static agerSingleton getInstance(){
        
return m_instance;
    }

       
public void refreshMap(Object key){
        
synchronized(map){
            
if(!map.contains(key))
                map.put(key,value);
//value为此时的实时数据
        }
 
    }

}
因为该类是单例,可能多线程并发访问map,map非线程安全,需要加线程安全关键字,否则就掉入了访问互斥资源的陷阱。
(3)陷阱三:非法逻辑陷阱
        这种情况一般是滥用单例模式造成的,下面考虑一种滥用单例的情况。下面的代码的作用是getValueByName后,马上printValue即完成操作流程。
public class EagerSingleton{
    
private static EagerSingleton m_instance=new EagerSingleton();
    
private String value=null;
   
private EagerSingleton(){};
   
public static agerSingleton getInstance(){
        
return m_instance;
    }

    
synchronized public void getValueByName(String name){
        value
=getByNameFromDateBase(name);
        
    }

    
public viod printValue(){
        System.out.println(
this.vaue);
    }

}

该类含有一私有属性value,在多线程环境下不能保证value值的合理逻辑,一线程getValueByName后,马上printValue,也有可能value的值已经被其他线程修改。这种情况就属于单例模式的滥用,该类根本不适合做成单例。
        消除非法逻辑的陷阱,可以通过将该类重构为纯粹的行为类完成。重构后的代码如下:

public class EagerSingleton{
    
private static EagerSingleton m_instance=new EagerSingleton();
   
private EagerSingleton(){};
   
public static agerSingleton getInstance(){
        
return m_instance;
    }

    
private String getValueByName(String name){
        
return getByNameFromDateBase(name);
        
    }

    
public viod printName(String name){
        String value
=getValueByName(String name);
        System.out.println(value);
    }

}

通过调用printName(String name)直接完成操作流程,将其中的私有属性处理成过程式的参数传递,将该类修改成纯粹的行为类。

        含有私有属性并且含有对它赋值操作的类并非都会调入该陷阱,构造函数里进行对私有属性赋值不会引起非法逻辑,如下代码

public class EagerSingleton{
    
private static EagerSingleton m_instance=new EagerSingleton();
    
private HashMap map==new HashMap();
    
    private
 EagerSingleton(){
        map.put(key,value);
//value为此时的实时数据
    }

   
public static agerSingleton getInstance(){
        
return m_instance;
    }

}

构造函数里不必要加线程安全关键字也可以保证线程安全,因为类加载器是线程安全的,EagerSingleton只会在类加载的时候实例化一次,这样不会出现单例模式的线程不安全,也不会造成非法逻辑。
(4)陷阱四:单例陷阱的传递
        当含有对象作为单例类的私有属性时,陷阱不仅会出现在该类本身,还会传递到私有对象所在的类中。看如下代码:

public class EagerSingleton{
    
private static EagerSingleton m_instance=new EagerSingleton();
    
private NewClass newClass=nll;
   
private EagerSingleton(){
        newClass
=new NewClass();
    }
;
   
public static agerSingleton getInstance(){
        
return m_instance;
    }

   
public viod printName(String name){
        String value
=newClass.operationByNameAndReturnValue(String name);
        System.out.println(value);
    }

}
乍一看,代码中除了构造函数对私有属性进行了初始化操作,其他地方没有对私有属性的赋值,不会引起非法逻辑陷阱。其实这个赋值操作可能隐含在newClass.operationByNameAndReturnValue(String name)操作,只有保证了NewClass的operationByNameAndReturnValue操作不会对它的私有属性赋值操作,才能保证真正的合理逻辑。同样,只有保证NewClass的operationByNameAndReturnValue操作没有掉入访问互斥资源陷阱,才能真正保证EagerSingleton没有掉入该陷阱。
        消除该陷阱的方法:(1)类方法的名称要合理,比如纯粹的行为方法名:interprete,excute,operation之类的方法中就不该含有对私有属性直接或者间接的赋值操作,每个方法的责任要明确。(2)单例类中尽量不要含有非单例类的实例作为私有属性(容器类除外),一定要有类的实例作为私有属性的时候,重新审视这个作为私有属性的类,是不是也应该设计成单例类;或者保证对它的初始化赋值限制在构造函数内。

posted @ 2006-08-26 11:26 JavaExplore 阅读(4884) | 评论 (13)编辑 收藏