简介
享元模式是对象池的一种实现,它的英文名叫Flyweight, 代表轻量级的意思。享元模式用来尽可能减少内存使用量,它适合用于大量重复对象的场景,来缓存可共享的对象,达到对象共享,避免创建过多对象的效果,这样一来就可以提升性能,避免内存移除等.
它的UML类图如下:
享元模式的简单示例
这个是一个买车票的栗子,客户端通过输入起始地和目的地到服务器,服务器返回车票价格信息,一次请求总会产生一个车票价格信息对象,如果是成千上万的用户不停的请求势必会使得服务器产生大量的重复对象,为了避免不必要的内存开销,可以使用享元模式来优化这种情况.
public interface Ticket {
void showTicketInfo(String bunk);
}
火车票实现类
public class TrainTicket implements Ticket{
public String from;
public String to;
public String bunk;
public int price;
public TrainTicket(String from, String to) {
this.from = from;
this.to = to;
}
@Override
public void showTicketInfo(String bunk) {
price = new Random().nextInt(300);
System.out.println("购买 从 "+from+" 到 "+to+" 的 "+bunk+" 火车票"+",价格 : "+price);
}
}
public class TicketFactory {
public static Ticket getTicket(String from,String to){
return new TrainTicket(from,to);
}
}
以上面这种方式去产生TrainTicket,如果客户端请求多次势必会产生大量的内容重复的对象,这样当这些对象无用后GC回收将会非常耗费资源.下面使用享元模式来优化这个问题:
public class TicketFactoryFw {
static Map<String,Ticket> sTicketMap = new ConcurrentHashMap<>();
public static Ticket getTicket(String from, String to){
String key = from + "-" + to;
if (sTicketMap.containsKey(key)){
System.out.println("使用缓存 ==> "+key);
return sTicketMap.get(key);
}else{
System.out.println("创建对象 ==> "+key);
Ticket ticket = new TrainTicket(from,to);
sTicketMap.put(key,ticket);
return ticket;
}
}
}
这种方式把对象缓存到了sTicketMap, key为 "from + "-" + to",这样避免了重复的起始地和目的地产生重复对象的情况.
Java中用到的享元模式
public class Test {
public static void testString(){
String str1 = new String("abc");
String str2 = "abc";
String str3 = new String("abc");
String str4 = "ab"+"c";
//使用equals判断字符值
System.out.println(str1.equals(str2));
System.out.println(str1.equals(str3));
System.out.println(str3.equals(str2));
//等号判断,判定两个对象是不是同一个地址
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str3 == str2);
System.out.println(str4 == str2);
}
}
最后输出
true
true
true
false
false
false
true
总结
前面三个输出结果不必过多解释,equals就是比较内容的, ==则是比较引用是否相同,后面的输出结果是因为,java中有个String池,这个String池其实就是利用享元模式,同样的字符串会从String内获得,那么str2 和 str4是从String池取得的相同的对象,所以输出true.
【附录】