设计模式(五)享元模式

版权声明:转载必须注明本文转自晓_晨的博客: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


UML图
设计模式(五)享元模式_第1张图片

在这里攻击力,材料和攻速属于内蕴,创建后就不可修改了,而耐久度属于外韵,可以影响武器最终的攻击力。单纯享元就是这样,其实可以理解为用一个工厂管理单例的模式,单例用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图
设计模式(五)享元模式_第2张图片
这里LZ符合类选择用List,因为LZ把这个理解成双手都能持武器(拿2把剑),可以为2把木剑,然后最后生成的对象,CompositeSword里面list的Sword对象是共享的,但生成出来的CompositeSword每个都是不一样的。然后每把剑都有自己的耐久度,我们可以通过list传入耐久度,然后在CompositeSword里遍历,依次传入耐久度调用attack。

总结

1、享元模式适用环境

  
  (1)一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费;
  (2)对象的大部分状态都可以外部化,可以将这些外部状态传入对象中(细粒度对象);
  (3)使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。

2、享元模式的优点

  (1)它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份;
  (2)享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。

3、享元模式的缺点

  (1)享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化;
  (2)为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。

Git地址

本篇实例Github地址:https://github.com/stackisok/Design-Pattern/tree/master/src/flyweight

回到最上方


有什么不懂或者不对的地方,欢迎留言。
喜欢LZ文章的小伙伴们,可以关注一波,也可以留言,LZ会回你们的。
觉得写得不错的小伙伴,欢迎转载,但请附上原文地址,谢谢^_^!

你可能感兴趣的:(JAVA设计模式,java设计模式)