二十二、享元模式——设计模式学习笔记

作为一个编程菜鸟,过去在学习设计模式的时候,老师给推荐了一本《大话设计模式》。阅读以后受益匪浅,可惜当初没有坚持看完。
最近有时间了,又重新捡起来学习了一遍,整理了一下笔记,由于本人能力有限,欢迎大家批评指正。

1.享元模式 Flyweight Pattern

  • 运用共享技术有效地支持大量细粒度的对象。
  • 享元模式使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于只是因重复而导致使用无法令人接受的大量内存的大量物件。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。
  • 内蕴状态(内部状态)存储在享元内部,不会随环境的改变而有所不同,是可以共享的。
  • 外蕴状态(外部状态)是不可以共享的,它随环境的改变而改变,因此外蕴状态是由客户端来保持(因为环境的变化是由客户端引起的)。

2.uml类图

二十二、享元模式——设计模式学习笔记_第1张图片

3.组成

(1)Flyweight

所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态。

(2)ConcreteFlyweight

是继承Flyweight超类或实现Flyweight接口,并为内部状态增加存储空间。

(3)UnshareConcreteFlyweight

是志那些不需要共享的Flyweight子类。因为Flyweight接口共享成为可能,但它并不强制共享。

(4)FlyweightFactory

是一个享元工厂,用来创建并管理Flyweight对象,它主要是用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。

(5)Client

维护队所有享元对象的引用,而且还需要存储对应的外部状态。

4.内部状态与外部状态

享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,有时就能够受大幅度地减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目。

5.应用场景

  • 如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时就应该考虑使用;还有就是对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。
  • 使用享元模式需要维护一个记录了系统已有的所有享元的列表,而这本身需要消耗资源,另外享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。因此,应当在有足够多的对象实例可供共享时才值得使用享元模式。

6.实例

(1)需求

帮多人做网站,要求差别不大,对于不同企业的网站,数据有所不同。

(2)uml类图

二十二、享元模式——设计模式学习笔记_第2张图片

(3)代码

a.外部状态用户类
package com.longinus.fp;
//用于网站的客户账号,是“网站”类的外部状态
public class User {
    private String name;

    public User(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
b.网站享元抽象类
package com.longinus.fp;
public abstract class WebSite {
    //“使用”方法需要传递“用户”对象
    public abstract void use(User user);
}
c.具体网站享元类
package com.longinus.fp;
public class ConcreteWebSite extends WebSite {
    private String name;

    public ConcreteWebSite(String name) {
        this.name = name;
    }

    @Override
    public void use(User user) {
        System.out.println("网站分类:" + name + " 用户:" + user.getName());
    }
}
d.网站享元工厂类
package com.longinus.fp;
import java.util.HashMap;
import java.util.Map;
public class WebSiteFactory {
    private Map map = new HashMap<>();
    //获得网站分类
    public WebSite getWebSiteCategory(String key) {
        if(!map.containsKey(key)){
            map.put(key, new ConcreteWebSite(key));
        }
        return map.get(key);
    }
    //获得网站分类总数
    public int getWebSiteCount() {
        return map.size();
    }
}
e.客户端
package com.longinus.fp;
public class Test {
    public static void main(String[] args) {
        WebSiteFactory factory = new WebSiteFactory();

        WebSite w1 = factory.getWebSiteCategory("产品展示");
        w1.use(new User("李电"));

        WebSite w2 = factory.getWebSiteCategory("产品展示");
        w2.use(new User("李闪"));

        WebSite w3 = factory.getWebSiteCategory("产品展示");
        w3.use(new User("李雷"));

        WebSite w4 = factory.getWebSiteCategory("博客");
        w4.use(new User("李鸣"));

        WebSite w5 = factory.getWebSiteCategory("博客");
        w5.use(new User("韩梅梅"));

        WebSite w6 = factory.getWebSiteCategory("博客");
        w6.use(new User("韩花花"));

        System.out.println("得到网站分类总数为" + factory.getWebSiteCount());
    }
}
f.输出结果
网站分类:产品展示 用户:李电
网站分类:产品展示 用户:李闪
网站分类:产品展示 用户:李雷
网站分类:博客 用户:李鸣
网站分类:博客 用户:韩梅梅
网站分类:博客 用户:韩花花
得到网站分类总数为2

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