首页 > 其他分享 >Day11-设计模式之享元模式

Day11-设计模式之享元模式

时间:2023-07-05 21:22:41浏览次数:42  
标签:享元 状态 对象 网站 Day11 设计模式 type public

设计模式之享元模式

一、意图

在面向对象系统的设计和实现中,创建对象是最为常见的操作。这里面就有一个问题:如果一个应用程序使用了太多的对象,就会造成很大的存储开销。特别是对于大量轻量级(细粒度)的对象,比如在文档编辑器的设计过程中,我们如果为每个字母创建一个对象的话,系统可能会因为大量的对象而造成存储开销的浪费。

例如一个字母“a”在文档中出现了10000次,而实际上我们可以让这一万个字母“a”共享一个对象,当然因为在不同的位置可能字母“a”有不同的显示效果(例如字体和大小等设置不同),在这种情况下我们可以将对象的状态分为“外部状态”和“内部状态”,将可以被共享(不会变化)的状态作为内部状态存储在对象中,而外部状态(例如上面提到的字体、大小等)我们可以在适当的时候将外部对象作为参数传递给对象(例如在显示的时候,将字体、大小等信息传递给对象)。

  • 享元模式(Flyweight Pattern) 也叫蝇量模式,是一种结构型模式,“享”就表示共享,“元”表示对象。运用共享技术有效地支持大量细粒度的对象,享元模式能够解决重复对象的内存浪费的问题,当系统中有大量相似对象,需要缓冲池时,不需总是创建新对象,可以从缓冲池里拿。这样可以降低系统内存,同时提高效率。
  • 解决思路:复用对象最简单的方式是,用一个 HashMap 来存放每次新生成的对象。每次需要一个对象的时候,先到 HashMap 中看看有没有,如果没有,再生成新的对象,然后将这个对象放入 HashMap 中。

二、角色职责

  • Flyweight(抽象享元角色):享元对象的抽象基类或者接口,声明具体享元角色需要实现的方法,这些方法可以向外界提供对象的内部状态的操作,设置外部状态

    • 内部状态(intrinsic):是享元对象可共享的属性,存储在享元对象内部并且不会随环境改变而改变。
    • 外部状态(extrinsic):是对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状态。
  • ConcreteFlyweight( 具体享元角色): Flyweight的具体实现,实现抽象角色定义的方法。 为内部状态提供成员变量进行存储。

  • UnsharedConcreteFlyweigh( 非共享的享元角色)不能被共享的子类,可以设计为非共享享元类。

  • FlyweightFactory(享元工厂角色): 负责管理享元对象池和创建享元对象,就是构造一个池容器,同时提供从池中获得对象的方法,

    • 当请求获取一个享元对象时,享元工厂判断是否存在该享元对象,如果存在则返回;如果不存在的话,则创建一个新的享元对象,保存到池容器中,然后返回给请求者。
    • 享元池一般设计成键值对。
    • 享元模式一般都是和工厂模式一起出现

三、类图

img

四、代码实现

场景:现有一外包公司,帮客户A做了一个产品展示网站,网站做好后更多客户觉得效果不错,也希望做个类似网站,但不同的是有客户要求以网页形式发布、有客户要求以微信公众号形式发布、有客户希望以博客形式发布。合理设计达到代码复用,灵活易维护扩展。

一般解法

直接复制粘贴一份,然后再根据客户不同要求,进行定制修改,给每一个网站租用了一个空间。
示意图如下:

img

问题分析:
首先需要的网站结构相似度很高(设普通网站,非高访问大并发),如果分成多个虚拟空间来处理,相当于一个相同网站的实例对象很多,造成服务器的资源浪费。

解决思路:
全部整合到一个网站中,共享其相关的代码和数据,对于硬盘、内存、CPU、数据库空间等服务器资源都可以达成共享,减少服务器资源。对于代码来说,由于是一份实例,维护和扩展都更加容易=》享元模式。

  1. 抽象类:
public abstract class WebSite {
    public abstract void use(User user);
}

  1. 抽象实现子类
public class ConcreteWebSite extends WebSite{
    //内部状态
    private String type="";//网站的发布形式

    //创建网站的构造器
    public ConcreteWebSite(String type) {
        this.type = type;
    }

    @Override
    public void use(User user) {
        System.out.println("网站的发布形式为:"+type+",使用者为:"+user.getName());
    }
}

  1. 享元工厂类
import java.util.HashMap;

public class WebSiteFactory {
    //集合,充当池容器的作用
    private HashMap<String,ConcreteWebSite> pool = new HashMap<>();

    //根据网站的类型,返回一个网站,如果没有就创建一个网站放入池中,并返回
    public WebSite getWebSiteCategory(String type){
        if(!pool.containsKey(type)){
            pool.put(type,new ConcreteWebSite(type));
        }
        return pool.get(type);
    }

    //获取网站分类的总数 (池中有多少个网站类型)
    public int getWebSiteCount(){
        return pool.size();
    }

}

  1. 不可共享类
@Data
public class User {//外部状态

    private String name;

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

}

  1. 客户端调用类
public class Client {

    public static void main(String[] args) {
        //创建一个工厂实例
        WebSiteFactory webSiteFactory = new WebSiteFactory();

        WebSite webSite1 = webSiteFactory.getWebSiteCategory("网页");
        webSite1.user(new User("客户A"));

        WebSite webSite2 = webSiteFactory.getWebSiteCategory("微信公众号");
        webSite2.user(new User("客户B"));

        WebSite webSite3 = webSiteFactory.getWebSiteCategory("微信公众号");
        webSite3.user(new User("客户C"));

        WebSite webSite4 = webSiteFactory.getWebSiteCategory("微信公众号");
        webSite4.user(new User("客户D"));

        System.out.println("网站的分类共:"+webSiteFactory.getWebSiteCount()+"种");

        System.out.println("webSite1-"+webSite1.hashCode());
        System.out.println("webSite2-"+webSite2.hashCode());
        System.out.println("webSite3-"+webSite3.hashCode());
        System.out.println("webSite4-"+webSite4.hashCode());
        
    }

五、享元模式的应用场景

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

六、总结

享元模式就是使相同的对象共享使用。

(一)优点

  • 极大减少内存中对象的数量,相同或相似对象内存中只存一份,降低程序内存的占用,增强程序的性能。

  • 外部状态相对独立,不影响内部状态

(二)缺点

  • 提高了系统复杂性,需要分离出外部状态和内部状态,而且外部状态不应该随内部状态改变而改变,否则导致系统的逻辑混乱。

标签:享元,状态,对象,网站,Day11,设计模式,type,public
From: https://www.cnblogs.com/coolsheep/p/17529823.html

相关文章

  • Day13-设计模式之命令模式
    设计模式之命令模式一、引例我们买了一套智能家电,有照明灯、风扇、冰箱、洗衣机,我们只要在手机上安装app就可以控制对这些家电工作。这些智能家电来自不同的厂家,我们不想对每一种家电都安装一个App,分别控制,我们希望只要一个app就可以控制全部智能家电。要实现一个app控制所......
  • Day12-设计模式之备忘录模式
    设计模式之备忘录模式一、引例案例引入游戏角色状态恢复问题游戏角色有攻击力和防御力,在大战Boss前保存自身的状态(攻击力和防御力),当大战Boss后攻击力和防御力下降,从备忘录对象恢复到大战前的状态。传统的设计方案传统的方式的问题分析一个对象,就对应一个保存对象状态......
  • Java基础-Day11
    Java基础-Day11关键字this知识点理解方式:3W:what?why?how?this的使用示例:this关键字的使用:1.this可以用来修饰:属性、方法、构造器2.this修饰属性和方法:this理解为:当前对象​ 在类的方法中,我们可以使用this.属性或this.方法的方式,调用当前对象的属性或方法。但......
  • JAVA设计模式之建造者模式
    设计模式设计模式(DesignPattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、......
  • DDD领域设计模式
    微服务设计为什么要选择DDD?其实最近几年微服务架构的思想越来越普及,很多企业已经或者尝试从单体架构向微服务架构转型。微服务也成为很多中大型企业实施中台战略的不二之选。但是在微服务实施过程中有很多问题,单体应用到底应该如何去拆分微服务?边界到底怎么划分?微服务这个微字到......
  • 画出创建型设计模式的类图
    工厂方法FactoryMethod抽象工厂AbstractFactory单例模式Singleton建造者模式Builder原型模式Prototype......
  • JAVA设计模式之工厂模式
    设计模式设计模式(DesignPattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、......
  • 画出结构型设计模式的类图
    装饰器模式Decorator适配器模式Adapter桥接模式Bridge组合模式Composite代理模式Proxy静态代理JDK动态代理享元模式Flyweight外观模式Facade ......
  • day11
    day11函数进阶目标:掌握函数相关易错点&项目开发必备技能。今日概要:参数的补充函数名,函数名到底是什么?返回值和print,傻傻分不清楚。函数的作用域1.参数的补充在函数基础部分,我们掌握函数和参数基础知识,掌握这些其实完全就可以进行项目的开发。今天的补充的内容属于......
  • 设计模式 - 观察者模式以及存在的问题
    观察者模式其实可以称之为发布订阅模型的,因为里面有一个Observable 和一个Observer ,我这个Observable为可以观察到的意思,意思就是对外可见的,所以可以称之为发布者(publisher),其他的Observer可以称之为订阅者(subscriber),是对外不可见的.1.JDK的观察者模式 jav......