设计模式——享元模式

享元模式(如果缓存中有从缓存中拿,缓存没有就创建)

场景:网站外包

image-20220529202407720

我们想要一个网站以不同的形式展现出来。

传统做法是每需要一个网站就new一个这样的对象出来,这样的缺点是系统内部会出现大量相似的对象,使得系统效率降低,要是网站出现了bug,所有创建的对象都要重新创建,维护起来会很麻烦。假如有多个用户想要以新闻的形式发布,我们可以让这些用于共享一个以新闻发布的网站,这样就不用重复地创建相同的对象,网站要是出现了bug,修改起来也会很容易,这也就是下面所说的享元模式

享元模式

也叫蝇量模式,常用于系统底层优化性能,解决重复对象的内存浪费问题,当系统中由大量相似对象,需要内存时,不需要总是创建新的对象,而是一次使用的时候,将创建的对象放入缓冲池中,其他人再使用的时候直接从缓冲池中那就行了,这样就可以避免创建大量的重复对象。享元模式在Java中用的非常多比如各种连接池(提前创建好连接对象,要用的时候从池中直接拿,用完再放回去),String类(使用的字符串都会从常量池中拿,如果没有则创建一个字符串放入常量池,再把它的引用拿过来赋值)

image-20220529203215220

image-20220529205036487

内部状态:对象的类别(黑白两种)

外部状态:对象赖以生存的,不可共享标记(在这个坐标上需要棋子时,直接从缓冲区中拿,而不需要再次创建对象)(谁来使用这个共享的对象)

实现

网站的抽象类:

@Data
public abstract class WebSite {
    private String type;
    abstract void use(User user);
}

网站具体的实现类:

public class ConcreteWebsite extends WebSite{
    ConcreteWebsite(String type){
        setType(type);
    }
    @Override
    void use(User user) {
        System.out.println("当前网站的类型是:"+getType()+"\n使用的用户是:"+user.getName());
    }
}

用户:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    String name;
}

网站工厂,里面封装了网站的使用池

其中内部模式是type,也就是网站的类型,而外部模式是用户(线程)。每个网站有不同的类型,而每个类型最多只会有一个示例,所有用户共享这些示例,这样就可以避免创建过多的重复对象,提供系统性能

public class WebFactory {

    private static final WebFactory webFactory=new WebFactory();
    private static final HashMap<String,WebSite> webSitePool=new HashMap<>(3);
    private WebFactory(){}

    public static WebFactory getWebFactory(){
        return webFactory;
    }
    public WebSite getWebSite(String type){
        if(webSitePool.containsKey(type)){
            return webSitePool.get(type);
        }else{
            WebSite webSite=new ConcreteWebsite(type);
            webSitePool.put(type,webSite);
            return webSite;
        }
    }
    public int getWebSiteCount(){
        return webSitePool.size();
    }
}

得到结果:

image-20220529220952727

微信形式的网站调用了两次,但是只创建了一个对象

是不是和Spring容器很像?Spring的整个框架就是基于享元模式来实现了,所有的组件都放在单例池中,如果我们设置的是单例对象,获取对象时会先从单例池中找,如果没有找到就创建一个组件。(当然,创建对象的流程远不止这些)

享元模式源码示例:Integer

image-20220529222834764

我们来查看valueof的源码

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

Integer在类加载的时候,会开一个数组存放值为[-128,127]的Integer对象,如果我们需要这个范围的Integer对象,它就会直接将缓存中的对象返回,如果不在这个返回内就会创建一个新的Integer对象。(因为[-128,127]使用频率较高),这也是x==z的原因,因为x,z获取的都是cache中的对象,所以是是同一个对象,而x1,x2因为不在[-128,127]这个范围内,所以会创建两个不同的对象

注意细节

image-20220529230345509

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值