大话设计模式读书笔记(享元模式)

人物:大鸟,小菜

事件:小菜最近接了点私活,是一个做网站的外包,刚开始是为一个客户做,后来另一个客户也需要做一个类似的网站,后面客户多了这样代码虽然结构类似但是多多少少都有些不一样了,而且很费租用空间,后期更是难以维护,在小菜给大鸟倾诉完之后,大鸟为小菜提供了一种新的设计模式:享元模式


享元模式:

1.用代码设计小菜实例

2.了解共享模式

3.通过共享模式改进小菜实例并小结

 

每个网站一个实例的设计实现

WebSite类,网站:

@Slf4j
public class WebSite {
    private String name = "";

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

    public void use() {
        log.info("网站分类:" + name);
    }
}

客户端代码:

public class WebSiteClient {
    public static void main(String[] args) {
        WebSite fx = new WebSite("产品展示");
        fx.use();
        WebSite fy = new WebSite("产品展示");
        fy.use();
        WebSite fz = new WebSite("产品展示");
        fz.use();
        WebSite fl = new WebSite("博客");
        fl.use();
        WebSite fm = new WebSite("博客");
        fm.use();
        WebSite fn = new WebSite("博客");
        fn.use();
    }
}

小菜:这样就做出3个产品展示,3个博客的网站

 

享元模式

1.概念:运用共享技术有效地支持大量细粒度的对象

2.结构图:

3.代码示例:

Flyweight类,是所有具体享元类的超类或接口

public abstract class Flyweight {
    public abstract void Operation(int extrinsicstate);
}

ConcreteFlyweight类,为内部状态增加存储空间:

@Slf4j
public class ConcreteFlyweight extends Flyweight {
    @Override
    public void Operation(int extrinsicstate) {
        log.info("具体Flyweight: " + extrinsicstate);
    }
}

UnsharedConcreteFlyweight类,指那些不需要共享的Flyweight子类:

@Slf4j
public class UnsharedConcreteFlyweight extends Flyweight {
    @Override
    public void Operation(int extrinsicstate) {
        log.info("不共享的具体Flyweight: " + extrinsicstate);
    }
}

FlyweightFactory类,是一个享元工厂,用来创建和管理FlyweightFactory,主要是确保合理共享Flyweight:

public class FlyweightFactory {
    private Hashtable flyweights = new Hashtable<>();

    public FlyweightFactory() {
        flyweights.put("X", new ConcreteFlyweight());
        flyweights.put("Y", new ConcreteFlyweight());
        flyweights.put("Z", new ConcreteFlyweight());
    }

    public Flyweight getFlyweight(String key) {
        return (Flyweight)flyweights.get(key);
    }
}

客户端代码:

public class WebSiteClient {
    public static void main(String[] args) {
        int extrinsicstate = 22;

        FlyweightFactory f = new FlyweightFactory();

        Flyweight fx = f.getFlyweight("X");
        fx.Operation(--extrinsicstate);

        Flyweight fy = f.getFlyweight("Y");
        fy.Operation(--extrinsicstate);

        Flyweight fz = f.getFlyweight("Z");
        fz.Operation(--extrinsicstate);

        UnsharedConcreteFlyweight uf = new UnsharedConcreteFlyweight();

        uf.Operation(--extrinsicstate);
    }
}

 

享元模式结合小菜实例

网站抽象类:

@Slf4j
public abstract class WebSite {
    public abstract void use();
}

具体网站类:

@Slf4j
public class ConcreteWebSite extends WebSite {
    private String name = "";

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

    @Override
    public void use() {
        log.info("网站分类:" + name);
    }
}

网站工厂类:

public class WebSiteFactory {
    private Hashtable flyweights = new Hashtable();

    public WebSite getWebSiteCategory(String key) {
        if (!flyweights.containsKey(key)) {
            flyweights.put(key, new ConcreteWebSite(key));
        }
        return (WebSite) flyweights.get(key);
    }

    public int getWebSiteCount() {
        return flyweights.size();
    }
}

客户端代码:

public class WebSiteClient {
    public static void main(String[] args) {
        WebSiteFactory f = new WebSiteFactory();

        WebSite fx = f.getWebSiteCategory("产品展示");
        fx.use();

        WebSite fy = f.getWebSiteCategory("产品展示");
        fy.use();

        WebSite fz = f.getWebSiteCategory("产品展示");
        fz.use();

        WebSite fl = f.getWebSiteCategory("博客");
        fl.use();

        WebSite fm = f.getWebSiteCategory("博客");
        fm.use();

        WebSite fn = f.getWebSiteCategory("博客");
        fn.use();
    }
}

最后输出的结果:

网站分类:产品展示
网站分类:产品展示
网站分类:产品展示
网站分类:博客
网站分类:博客
网站分类:博客
网站分类总数为2

大鸟:这样算是基本实现了享元模式共享对象的目的,不管建几个网站,只要key相同,那么就一样,这里只体现了相同的部分,但实际中不同企业可能需要的网站功能同,但是不同公司的账号,数据都是不同的,那你有考虑过怎么处理么,我再给你讲讲享元模式的内部状态和外部状态。

 

享元模式的内部状态和外部状态

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

    也就是说客户的状态就是外部状态,应该由专门的对象来处理。

于是小菜出了第三版:

1.代码结构图:

2.代码示例:

User类,用户类,用户网站的客户账号:

@Data
@Accessors(chain = true)
public class User {
    private String name;
}

网站抽象类:

@Slf4j
public abstract class WebSite {
//使用的方法需要传递用户对象
public abstract void use(User user); }

网站工厂类:

public class WebSiteFactory {
    private Hashtable flyweights = new Hashtable();

    public WebSite getWebSiteCategory(String key) {
        if (!flyweights.containsKey(key)) {
            flyweights.put(key, new ConcreteWebSite(key));
        }
        return (WebSite) flyweights.get(key);
    }

    public int getWebSiteCount() {
        return flyweights.size();
    }
}

客户端代码:

@Slf4j
public class WebSiteClient {
    public static void main(String[] args) {
        WebSiteFactory f = new WebSiteFactory();

        WebSite fx = f.getWebSiteCategory("产品展示");
        User user1 = new User().setName("小菜");
        fx.use(user1);

        WebSite fy = f.getWebSiteCategory("产品展示");
        User user2 = new User().setName("大鸟");
        fx.use(user2);

        WebSite fz = f.getWebSiteCategory("产品展示");
        User user3 = new User().setName("娇娇");
        fz.use(user3);

        WebSite fl = f.getWebSiteCategory("博客");
        User user4 = new User().setName("老顽童");
        fl.use(user4);

        WebSite fm = f.getWebSiteCategory("博客");
        User user5 = new User().setName("桃谷六仙");
        fm.use(user5);

        WebSite fn = f.getWebSiteCategory("博客");
        User user6 = new User().setName("南海鳄神");
        fn.use(user6);

        log.info("网站分类总数为{}", f.getWebSiteCount());
    }
}

结果输出:

网站分类:产品展示用户:小菜
网站分类:产品展示用户:大鸟
网站分类:产品展示用户:娇娇
网站分类:博客用户:老顽童
网站分类:博客用户:桃谷六仙
网站分类:博客用户:南海鳄神
网站分类总数为2

 

3.享元模式的应用场景

(1)理解:当一个应用程序使用了大量重复的对象,而这些大量的存储对象造成了很大开销时,享元模式就可以通过共享对象来避免创建过多对象。

(2)举例:String常量池、数据库连接池、缓冲池等等,或者你要开发一款五子棋游戏,理论上一盘棋有361个空格要创建361个对象,但用了共享模式后,只用创建两个即可。

(3)优点:减少了大量重复的代码,简化了代码的复杂的,而且减小了开销,节省了内存,提高了性能。

posted @ 2020-08-10 10:36  pmingup9012  阅读(102)  评论(0编辑  收藏  举报