JavaExplore

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

2006年8月24日

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

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

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

posted @ 2006-09-12 23:33 JavaExplore 阅读(425) | 评论 (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 .3.1 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 .3.2 Axis对象

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

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

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

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

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

2 . 4 子标题对象

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

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

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

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

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

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

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

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

posted @ 2006-09-01 23:08 JavaExplore 阅读(770) | 评论 (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 阅读(4977) | 评论 (13) | 编辑 收藏

最近发现一本<java与模式>,正好再温故一下当年的专业课内容,下面是这几天记的笔记.(并不是系统的讲解书中的内容)
一  综述:
1、不要使用接口定义常量
2、自己少用标志接口
3、不要继承具体类
4、类层次的中间节点应该是接口或者抽象类,叶子是具体类
5、子类应当扩展父类的责任,而不是覆写父类的责任
6、面向接口编程
7、不要滥用继承,组合优先于继承

java中设计不当的类:calendar:作为接口,含有与具体的历法(罗马历法)相关的常量,不能扩展到中国的阴历历法(不符合开闭原则)
                    properies类:滥用继承,继承至hashtable,应当使用聚合

8、笛比特法则:只与自己的直接朋友通信,不与陌生人通信(1)狭义笛比特法则:只与朋友通讯,通过自己的朋友传递间接的调用(2)结合依赖倒转原则修改:不必通过朋友传递间接的调用,通过陌生人的抽象接口调用陌生人的行为(依旧不能与具体的陌生人发生通信)
9、尽量降低类中成员的访问权限,不要设计退化类(类似c中struct)。
        java中的point2D以及Dinmension2D类有这种设计缺陷(不过这种情况问题不大)
10、如果多个具体的产品类没有共同的商业逻辑,就可以把它们抽象到一个接口中,如果有共同的商业逻辑,就把共同的部分抽象到抽象类中,共同的部分尽量向类继承层次的上层移动,以达到复用的目的
二   工厂模式
1、简单工厂模式:参与角色:工厂/抽象产品类/具体产品类

   缺点:添加新产品的时候,虽然产品相关代码符合开闭原则,但对工厂类本身并不符合,需要修改其中的产生产品方法或者添加新的产生方法(工厂里实现的不同造成的修改不同)来支持新的产品类
   退化方式:省略掉工厂角色,抽象产品类担任具体产品类的工厂角色:提供静态的getInstance方法,比如java类库中的DateFormat类,(本人认为这样很不符合开闭原则,父类中出现与具体子类相关的代码,不方便扩展,添加新产品的时候,修改的时候缺点与原简单工厂的工厂角色类似)

2、工厂方法模式:参与角色:抽象工厂类/具体工厂类/抽象产品类/具体产品类
     消除了简单工厂的缺点


3、抽象工厂模式:简单工厂模式与工厂方法模式的结合

4、单例模式:饿汉和懒汉两种,前者将本身对象作为静态私有属性事先生成,后者推迟到调用的时候,后者需要考虑多线程的时候,前面需要加线程安全关键字(注意),java中还是前者为优。
   不要滥用单例,只有系统要求只有一个类的实例的时候才调用
   有的单例可能有状态属性,这就为多例模式提供了可能
   含有私有属性的类作成单例的时候尤其要注意:一是私有属性的线程安全,确实需要的时候可以加线程安全关键字,比如系统中的log类,二是确认这些属性是不是可以所有线程共享的,类似普通类的static
三   各种具体模式(1)
1、建造模式:参与角色4个:指导者、抽象建造对象、具体建造对象、产品
      一个复杂的产品有很多的零部件,就可以使用具体的建造对象来一一构造
2、原始模式:深拷贝、浅拷贝
3、适配器模式:将adaptee类适配成目标接口
4、合成模式:参与角色:composite接口、树枝节点类、树叶节点类
      分成透明式和安全式两种,各有优缺点
      (1)前者将管理子对象的方法放到接口中,这样树型结构中的所有对象都是透明的,都可以统一调用,但是叶节点并没有管理子对象的能力,因此透明但不安全
      (2)后者将管理子对象的方法下放到树枝节点类中,这样安全但不透明
5、装饰模式:继承已有类的接口,提供和已有类相同的方法,并对已有类的功能提供扩展(通过组合已有对象,调用已有对象方法的时候加入新的代码)
      (1)透明的装饰模式(纯粹的装饰模式):装饰类、被装饰类继承于同一接口,而且装饰类只实现接口的方法,不提供额外方法的实现,调用该类的时候使用接口声明调用(实例化当然还是自己的构造函数),即该类的所有方法都是透明的
      (2)半透明的装饰模式(退化的装饰模式):装饰类、被装饰类继承于同一接口,装饰类不仅实现接口的方法,还提供额外方法的实现,这样要调用它独特的方法的时候就必须使用它本身来调用,退化到一半装饰模式、一半适配器模式。

posted @ 2006-08-24 21:25 JavaExplore 阅读(2165) | 评论 (6) | 编辑 收藏