版权声明:转载必须注明本文转自晓_晨的博客:http://blog.csdn.net/niunai112
目录
- 目录
- 导航
- 前言
- 单纯享元模式
- 复合享元模式
- 总结
- 1、享元模式适用环境
- 2、享元模式的优点
- 3、享元模式的缺点
- Git地址
设计模式之六大设计原则
设计模式(一)单例模式
设计模式(二)工厂模式
设计模式(三)策略模式
设计模式(四)适配器模式
设计模式(五)享元模式
设计模式(六)建造者模式
设计模式(七)原型模式
设计模式(八)桥接模式
设计模式(九)外观模式
设计模式(十)组合模式
设计模式(十一)装饰器模式
设计模式(十二)代理模式
设计模式(十三)迭代器模式
设计模式(十四)观察者模式
设计模式(十五)中介者模式
设计模式(十六)命令模式
设计模式(十七)状态模式
设计模式(十八)访问者模式
设计模式(十九)责任链模式
设计模式(二十)解释器模式
设计模式(二十一)备忘录模式
设计模式(二十二)模板模式
设计模式总结篇(为什么要学习设计模式,学习设计模式的好处)
今天LZ来给大伙介绍下享元模式,这个设计模式主要用于减少创建对象的数量,以减少内存占用和提高性能。在JAVA中也有很广泛的使用,比如Integer的缓存机制,在加载的时候就已经为我们初始化好了-128 到 +127的实例,放在了缓存中,当我们要使用这里面的数时,就会直接去缓存中拿对象,而不用重新实例化。这里考虑了使用的程度,以及缓存大小给内存带来的压力,只实例化了-128到+127,当然你也可以通过
-Djava.lang.Integer.IntegerCache.high来修改来适应你系统的需求。
这里扯远了,LZ继续介绍享元模式,模式最大的核心在于共享共同使用的对象。LZ这里以自己的理解来给大家介绍以下享元模式
当我们玩网游的时候,一般新手会送一把木剑。然后木剑又是非常容易得到的,所以背包里会有很多把木剑,这个时候,假设你的背包非常大,那每把木剑都实例一个木剑对象的话,你的内存有很大一部分都是在浪费,因为存了重复的东西。但假如我们把木剑的属性分开来,把不变的东西通过缓存共享(比如剑的攻击速度,剑的材料,剑的攻击力),只实例化变的东西(剑的耐久度),那就大大减少了内存的压力。
/***
*
*@Author ChenjunWang
*@Description:
*@Date: Created in 18:33 2018/3/18
*@Modified By:
*
*/
abstract class Sword {
private int aggressivity;
private String speed;
private String material;
Sword(int aggressivity, String speed, String material){
this.aggressivity = aggressivity;
this.speed = speed;
this.material = material;
}
public int attack(int Durability) {
if (Durability>50)
return this.getAggressivity();
else if (Durability > 0 )
return this.getAggressivity() / 2;
return 0;
}
public int getAggressivity() {
return aggressivity;
}
public String getSpeed() {
return speed;
}
public String getMaterial() {
return material;
}
}
/***
*
*@Author ChenjunWang
*@Description:
*@Date: Created in 18:39 2018/3/18
*@Modified By:
*
*/
public class WoodSword extends Sword {
public WoodSword(int aggressivity, String speed, String material) {
super(aggressivity, speed, material);
}
}
/***
*
*@Author ChenjunWang
*@Description:
*@Date: Created in 18:59 2018/3/18
*@Modified By:
*
*/
public class IronSword extends Sword {
IronSword(int aggressivity, String speed, String material) {
super(aggressivity, speed, material);
}
}
/***
*
*@Author ChenjunWang
*@Description:
*@Date: Created in 18:48 2018/3/18
*@Modified By:
*
*/
public class SwordFactory {
private static Map map = new HashMap<>();
static Sword getSword(String s){
Sword sword = map.get(s);
if (sword != null)
return sword;
if (s.equals("wood"))
sword = new WoodSword(10,"快","木头");
else if (s.equals("iron"))
sword = new IronSword(50,"较快","铁");
if (sword == null)
return null;
map.put(s,sword);
return sword;
}
}
/***
*
*@Author ChenjunWang
*@Description:
*@Date: Created in 18:47 2018/3/18
*@Modified By:
*
*/
public class Test {
public static void main(String[] args) {
Sword woodSword = SwordFactory.getSword("wood");
System.out.println("耐久度为100时,实际攻击力为:" + woodSword.attack(100));
Sword woodSword2 = SwordFactory.getSword("wood");
System.out.println("耐久度为50时,实际攻击力为:" + woodSword2.attack(50));
System.out.println("woodSword 和 woodSword2 是否是同一个对象?" + (woodSword == woodSword2));
}
}
运行结果如下:
------------------------------------------------------
耐久度为100时,实际攻击力为:10
耐久度为50时,实际攻击力为:5
woodSword 和 woodSword2 是否是同一个对象?true
在这里攻击力,材料和攻速属于内蕴,创建后就不可修改了,而耐久度属于外韵,可以影响武器最终的攻击力。单纯享元就是这样,其实可以理解为用一个工厂管理单例的模式,单例用map来保存,然后工厂根据需要给出相应的实例。可能这个网游的例子不是很好,因为背包有限,但是让我们假设背包是无限的,我们背包每多一把木剑,就节省了不少内存空间,这样子来想,是不是给我们的内存减少了很大的负担呢。
有的时候需要组合一些享元,然后通过一个组合类来共同管理
/***
*
*@Author ChenjunWang
*@Description:
*@Date: Created in 19:36 2018/3/18
*@Modified By:
*
*/
public class CompositeSword extends Sword {
private List swordList = new LinkedList<>();
public CompositeSword(){
super();
}
public void add(Sword sword){
swordList.add(sword);
}
public void attack(List Durability) {
for (int i = 0; i < swordList.size(); i++){
System.out.println(swordList.get(i).getMaterial() + swordList.get(i).attack(Durability.get(i)));
}
}
}
/***
*
*@Author ChenjunWang
*@Description:
*@Date: Created in 19:36 2018/3/18
*@Modified By:
*
*/
public class CompositeSword extends Sword {
private List swordList = new LinkedList<>();
public CompositeSword(){
super();
}
public void add(Sword sword){
swordList.add(sword);
}
public void attack(List Durability) {
for (int i = 0; i < swordList.size(); i++){
System.out.println("耐久度为"+ Durability.get(i) + "实际攻击力为:" + swordList.get(i).attack(Durability.get(i)));
}
}
}
/***
*
*@Author ChenjunWang
*@Description:
*@Date: Created in 18:47 2018/3/18
*@Modified By:
*
*/
public class Test {
public static void main(String[] args) {
Sword woodSword = SwordFactory.getSword("wood");
System.out.println("耐久度为100时,实际攻击力为:" + woodSword.attack(100));
Sword woodSword2 = SwordFactory.getSword("wood");
System.out.println("耐久度为50时,实际攻击力为:" + woodSword2.attack(50));
System.out.println("woodSword 和 woodSword2 是否是同一个对象?" + (woodSword == woodSword2));
List list = new ArrayList<>();
list.add("wood");
list.add("wood");
CompositeSword composite = SwordFactory.getComposite(list);
List d = new ArrayList<>();
d.add(100);
d.add(50);
composite.attack(d);
}
}
运行结果如下
------------------------------
耐久度为100时,实际攻击力为:10
耐久度为50时,实际攻击力为:5
woodSword 和 woodSword2 是否是同一个对象?true
耐久度为100实际攻击力为:10
耐久度为50实际攻击力为:5
URL图
这里LZ符合类选择用List,因为LZ把这个理解成双手都能持武器(拿2把剑),可以为2把木剑,然后最后生成的对象,CompositeSword里面list的Sword对象是共享的,但生成出来的CompositeSword每个都是不一样的。然后每把剑都有自己的耐久度,我们可以通过list传入耐久度,然后在CompositeSword里遍历,依次传入耐久度调用attack。
(1)一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费;
(2)对象的大部分状态都可以外部化,可以将这些外部状态传入对象中(细粒度对象);
(3)使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。
(1)它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份;
(2)享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
(1)享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化;
(2)为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。
本篇实例Github地址:https://github.com/stackisok/Design-Pattern/tree/master/src/flyweight
有什么不懂或者不对的地方,欢迎留言。
喜欢LZ文章的小伙伴们,可以关注一波,也可以留言,LZ会回你们的。
觉得写得不错的小伙伴,欢迎转载,但请附上原文地址,谢谢^_^!