23种设计模式
Flyweight
n. (拳击或其他比赛中的)特轻量级选手,次最轻量级选手(体重48至51公斤) ;(拳击或其他比赛中的)特轻量级,蝇量级
1 Flyweight 定义
避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类)。
2 为什么使用?
面向对象语言的原则就是一切都是对象,但是如果真正使用起来,有时对象数可能显得很庞大。比如字处理软件,如果以每个文字都作为一个对象,几千个字,对象数就是几千,无疑耗费内存,那么我们还是要"求同存异",找出这些对象群的共同点,设计一个元类,封装可以被共享的类;另外,还有一些特性是取决于应用(context),是不可共享的,这也Flyweight 中两个重要概念内部状态 intrinsic 和外部状态 extrinsic 之分。
说白点,就是先捏一个的原始模型,然后随着不同场合和环境,再产生各具特征的具体模型,很显然,在这里需要产生不同的新对象,所以 Flyweight 模式中常出现 Factory 模 式.Flyweight 的内部状态是用来共享的,Flyweight factory 负责维护一个Flyweight pool(模式池)来存放内部状态的对象。
Flyweight模式是一个提高程序效率和性能的模式,会大大加快程序的运行速度.应用场合很多:比如你要从一个数据库中读取一系列字符串,这些字符串中有许多是重复的,那么我们可以将这些字符串储存在Flyweight池(pool)中。
3 如何使用?
比较抽象 ,可以直接看4应用举例
//1我们先从 Flyweight 抽象接口开始:
package xx.study.design.flyweight.case1;
public interface Flyweight {
/**
* 操作
* @param state
*/
public void operation(ExtrinsicState state);
}
//2用于本模式的抽象数据类型(自行设计)
package xx.study.design.flyweight.case1;
/**
* 固有属性 用于本地模式的抽象数据
*/
public interface ExtrinsicState {
}
//3下面是接口的具体实现(ConcreteFlyweight) ,并为内部状态增加内存空间,
//ConcreteFlyweight 必须是可共享的,它保存的任何状态都必须是内部(intrinsic),
//也就是说,ConcreteFlyweight 必须和它的应用环境场合无关.
package xx.study.design.flyweight.case1;
/**
* 具体享元 具体享元类 享原类
* ,ConcreteFlyweight 必须和它的应用环境场合无关.
*/
public class ConcreteFlyweight implements Flyweight{
//内部状态
private IntrinsicState state;
public void operation(ExtrinsicState state) {
//具体操作
}
}
//4当然,并不是所有的 Flyweight 具体实现子类都需要被共享的,所以还有另外一种不
//共享的 ConcreteFlyweight:
package xx.study.design.flyweight.case1;
/**
* 当然,并不是所有的 Flyweight 具体实现子类都需要被共享的,所以还有另外一种不
* 共享的 ConcreteFlyweight:
*/
public class UnsharedConcreteFlyweight implements Flyweight{
public void operation(ExtrinsicState state) {
}
}
//5 Flyweight factory 负责维护一个 Flyweight 池(存放内部状态),当客户端请求
//一个共享 Flyweight 时,这个 factory 首先搜索池中是否已经有可适用的,如果
//有,factory 只是简单返回送出这个对象,否则,创建一个新的对象,加入到池中,再返回送
//出这个对象池
package xx.study.design.flyweight.case1;
import java.util.Hashtable;
/**
*/
public class FlyweightFactory {
//Flyweight pool
private Hashtable flyweights = new Hashtable();
public Flyweight getFlyweight( Object key ) {
Flyweight flyweight = (Flyweight) flyweights.get(key);
if( flyweight == null ) {
//产生新的 ConcreteFlyweight
flyweight = new ConcreteFlyweight();
flyweights.put( key, flyweight );
}
return flyweight;
}
}
//6
//至此,Flyweight 模式的基本框架已经就绪,我们看看如何调用:
//从调用上看,好象是个纯粹的 Factory 使用,但奥妙就在于 Factory 的内部设计上。
package xx.study.design.flyweight.case1;
public class FlyweightDemo {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
Flyweight fly1 = factory.getFlyweight( "Fred" );
Flyweight fly2 = factory.getFlyweight( "Wilma" );
}
}
4 应用举例
网易云上有很多歌曲,缓存所有歌曲时,每个歌曲的歌词不相同,但是歌手可以是相同的,可以抽取出来;实现上述思想。
1原始类
package xx.study.design.flyweight.case2;
/**
* 唱片 相当于Flyweight 元类
*/
public class Song {
private String title;
private int year;
private Artist artist;
public String getTitle() {
return title;
}
public int getYear() {
return year;
}
public Artist getArtist() {
return artist;
}
public void setTitle(String t){
title = t;
}
public void setYear(int y){
year = y;
}
public void setArtist(Artist a){
artist = a;
}
}
2 固有类
package xx.study.design.flyweight.case2;
/**
* 将"歌唱者姓名"作为可共享的 ConcreteFlyweight:
*/
public class Artist {
//内部状态
private String name;
// 歌手是不变的
String getName(){
return name;
}
private int age;
Artist(String n,int age){
this.name = n;
this.age=age;
}
}
3 工厂类 抽取缓存下来
package xx.study.design.flyweight.case2;
import java.util.Hashtable;
public class ArtistFactory {
Hashtable pool = new Hashtable();
public Artist getArtist(String key,int age){
Artist result;
result = (Artist)pool.get(key);
////产生新的 Artist
if(result == null) {
result = new Artist(key,age);
pool.put(key,result);
}
return result;
}
}
4 使用
package xx.study.design.flyweight.case2;
public class cacheSongDemo {
public static void main(String[] args) {
ArtistFactory aFactory=new ArtistFactory();
//歌曲1 2 指向同一对象
Song song1=new Song();
Song song2=new Song();
song1.setArtist( aFactory.getArtist("周杰伦",18));
song2.setArtist( aFactory.getArtist("周杰伦",18));
}
}