`
程序员种康
  • 浏览: 7358 次
  • 性别: Icon_minigender_1
  • 来自: 南京
最近访客 更多访客>>
社区版块
存档分类
最新评论

也谈设计模式(Flyweight)

阅读更多
  对于设计模式我一直都在悟,说实在话,设计模式并不能让你的代码越来越简单,反而会让其复杂化,理解设计模式不难,吸收设计模式是痛苦的过程。
  设计模式是实践的产物,有需求才有改进,是一种聪明的偷懒方法,gof的设计模式比较抽象化,看看就知道是博士创作出来的东西,高度抽象形成理论,而理论是比较难于理解的,今天我斗胆也来谈谈对设计模式的一点感悟,说实话,现阶段我对设计模式的理解和吸收还在一个比较初级的阶段,所以我开篇说了“悟”,所以有什么说的不对,写的不好的地方还需要各位朋友的支持和改正。
  废话少说了,今天接触到了flyweight(元享模式),于是我先不急看手边的理论,想先查查资料,看看有什么比较通俗易懂,一针见血的好文,先让我有个直观的感受,回头再结合理论做深入的研究,这是我习惯的学习过程,效果也是不错的,至少印象深刻。但是发现关于此模式的介绍并不多,而且内容差不多,虽然这样,但是看完了一些还是有了认识,学习是要有动力的,现在面临着系统的重构工作,我想这就是我的动力,学以致用,用过了才有资格说自己会了,用的好不好,对不对暂且不说,至少这个过程是有益的,是会促使人思考的,是追求良好设计思想,优秀程序结构的表现。设计模式是要思考的,我往往一个模式要想半天,并不是我想不通,看不懂,而是想它背后的许多,总是有许多为什么,呵呵。
  什么是flyweight(元享)模式,为什么要叫flyweight?
  flyweight如果用中文来说是“次最轻量级的拳击选手”的意思,一开始我就很纳闷,为什么取这样一个名字,然后再看看中文对于这种模式的解释,叫“元享”模式,又是一头雾水,虽然说名字只是个称谓,一个记号,但是我相信在给这种模式命名的时候,前辈们应该是考虑过要和这种模式的本质有所关联的,是要符合这种模式本身特点和气质的。看到后来,似乎对英文名和中文名有了那么点感觉,又或者说如果不叫这个名字还能叫什么。
  什么是flyweight(元享)模式呢?其实就是一种为了避免在我们的系统中产生大量重复对象的方法,也是一种追求解耦,实现封装抵抗需求变化的过程。
  因为名字之所以有轻量级这层含义,我个人理解是针对系统中这样的对象而言,它们容易被重复产生,因为它们自身比较单纯,本身的侵入性比较小,有一层“轻”的概念在里面,而中文名叫“元享”,分两层来理解,第一,元是什么?我把元认为就是这样的对象,我们为什么会重复创建这些对象,因为它们是本元,万物不离其本元,我给你元,至于你怎么变化,怎么给它添砖加瓦,怎么组合排列那是你的事情,我只负责给你我的这个元,打个比方,我们每个人都有多重角色,你是男人,也是父亲,还是儿子,又是丈夫,区分这些角色的原则是要看你在什么样的环境下,你和谁在一起,比如我是个歌手,我可以出一张JAZZ专辑,也可以出一张ROCK的,或者RAP的,只要你的实力够档次,所以我们会有各式各样的对象就出来,无非是你这个人加上点什么就成了什么,这里就会产生一个问题,如果你把我new在了办公室里我就成了工作时的我,把我new在家里,我就是家里的我了,如果你同时把我new在办公室和家里,就会有两个我,虽然这好像说不通,但是我们本身是不能分身的,在程序里我们完全有能力做到这点,这样不断的new下去会有大量的我出现在各个地方,发挥各种作用,这样多爽啊,呵呵!
  假如我能分身,那我不希望和这些特有的环境和物质相绑定来完成我的角色,为什么,因为联系的太过紧密,那是什么意思,其实就是高耦合。我需要一个地方来派发单纯的我,然后把我派到各个地方担任各个角色,(这不是工厂模式吗?)没错,元享模式就是应用了工厂模式,我就待在这个工厂里哪也不去,除非有命令,那我就出去。这里需要注意的是我的元神依然在工厂里,你忘记了吧,我会分身的,所以你在工厂外面的只是我的分身。
  继续往下吧,哎,解释个名字解释半天,看来我终究不是博士,抽象能力太差。。。
  文字的力量不及代码来的明显,让我举个例子,然后来看看代码。
  什么例子呢,我自己也不想想了,就用歌手出CD专辑这个例子吧!这样一句话落在我们程序员脑子里就很不一样了,你从这句话中体会到了什么?歌手,CD,或许还有歌,专辑名称等等。。。(万物皆对象)
  很好,看来你想象能力还真是不错呢,CD这个东西我们就来把他抽象一把,看代码:
 
 
  public abstact class CD{
      private Artist artist;
       private CDOtherThings	special;
       public CD(Artist artist,CDOtherThings special){
          this.artist=artist;
          this.special = special;
       }
       //忽略了get和set方法
       public void doSomeSpecial(CDOtherThings special);
  } 
  public class CDOtherThings {
      private String cd_name;
      private ArrayList<String> songsList;
      public CDOtherThings(String cdName,ArrayList<String> songsList){
          this.cd_name = cdName;
	 this.songsList = songsList;
      }
      public String getCd_name() {
	 return cd_name;
      }
      public void setCd_name(String cd_name) {
	 this.cd_name = cd_name;
      }
      public ArrayList<String> getSongsList() {
	 return songsList;
      }
      public void setSongsList(ArrayList<String> songsList) {
	 this.songsList = songsList;
      }
   }
  //再来个歌手类
  public class Artist {
      private String name;
      private String age;
      private String company;
      public Artist(String name){
          this.name=name;
      }
      public String getAge() {
          return age;
      }
      public void setAge(String age) {
          this.age = age;
      }
      public String getCompany() {
          return company;
      }
      public void setCompany(String company) {
          this.company = company;
      }
      public String getName() {
          return name;
      }
      public void setName(String name) {
          this.name = name;
      }
    }
  

  我刚才说了,歌手是一直要待在工厂里提供给外面的是分身了,那么让我们来搞个工厂吧,注意,这可以此模式的精髓哦!
 
  public class ArtistFactory {
	
      private Hashtable<String,Artist> artist_table;
	
      public Artist getArtist(String name){
          Artist artist = null;
	 if(artist_table==null){
	     artist_table = new Hashtable<String,Artist>();
	     artist = new Artist(name);
	     artist_table.put(name,artist);
	     return artist;
           }
           artist = artist_table.get(name);
	  if(artist==null){
	      artist = new Artist(name);
	      artist_table.put(name,artist);
	   }
	   return artist;
	}
  }

  我在这个工厂里维护了一个数据结构,我们的元神就待在这里,命令来了我们要看一下这个数据结构中有没有我们想要的元神,如果有就给他,其实给的是副本了,如果没有我们就创建一个给它,但是我们还要把它放在元神共存的这个数据结构里,这里,这个key就很重要了,我们方便起见就拿歌手名称来作为key去找本人咯,呵呵。
  接下来让我们继承一下这个CD类吧
 
 
  
public class CDChild extends CD{	
    public CDChild(Artist artist,CDOtherThings special){
        super(artist,special);    
    }
    public void doSomeSpecial(CDOtherThings special){
        String cd_name = special.getCd_name();
        ArrayList<String> songsList = special.getSongsList();
        if(cd_name==null||"".equals(cd_name)){
            System.out.println("no cd name!");
	   return;
	}
	if(songsList==null||songsList.size()==0){
	    System.out.println(cd_name+"no songs!");
	    return;
	}
	int size = songsList.size();
	for(int i=0;i<size;i++){
	    String songName = songsList.get(i);
	    System.out.println(songName);
	}
     }
  }
  //下面就是测试代码咯
  public class Test {
	
      public static void main(String[]args){
		
          ArrayList<String> songsList = new ArrayList<String>();
	 songsList.add("aSong");
	 songsList.add("bSong");
	 CDOtherThings special = new CDOtherThings("CD_NAME_ONE",songsList);
	 ArtistFactory factory = new ArtistFactory();
	 Artist artist = factory.getArtist("LP");
	 CD cd = new CDChild(artist,special);
	    cd.doSomeSpecial(special);
	 }
    }  
  

  此时,“LP”这个乐队在这里就出了这样一张“CD_NAME_ONE”这张专辑,但是不管我用这种方式给“LP”去发几张不同的专辑,“LP”在工厂里有一个元神。这就避免了重复创建“LP”。
  flyweight(享元)模式还有两个概念:
  1,intrinsic 内部状态
  2,extrinsic 外部状态
  其实就是Artist和CDOtherThings的意思,我是这么理解的。
  当然,此模式也可以不支持共享元神对象的,这里就不多做说明了,这里的不共享是指Artist对象,我可以待在那个数据结构中等待命令来调用我,也可以每次都new一下new一下,具体情况具体分析了。
  写完了,也不知道例子卡不恰当,表述的清楚不清楚,希望能对一些朋友有帮助,同时也是对自己学习的一个总结,相当于再一次学习和升华。
分享到:
评论
5 楼 xixix2004 2008-08-05  
你的例子里,歌手作为享元类,但是享元的实例不一定就只是由工厂类创建的。
也就是说某一歌手的本元可以被任意创建。
应该把歌手类做为工厂类的内部类来定义。
4 楼 xixix2004 2008-08-05  
意思是对的,不过例子有点复杂化了。
3 楼 tedeyang 2008-01-18  
我在blog发的回复,居然跑到论坛里了。
——javaeye的设计思路真的不错。
:)
2 楼 程序员种康 2008-01-18  
其实只想把自己对于这种模式的理解说一下而已,可能措辞方面还有一些问题,谢谢你的意见
1 楼 tedeyang 2008-01-17  
轻量级,很好理解的概念,干嘛说得这么复杂。
这东西起的作用大概就类似于公用函数,静态变量,指针。就像楼主所言,本来就只有一个我,干嘛要克隆呢。
概括来说,非常像“传值还是传地址”这样的经典语言问题,
只不过“Flyweight”上升到了OO级别。

相关推荐

Global site tag (gtag.js) - Google Analytics