• 设计模式之享元模式——初学


    1、引言
            一些大型的博客网站、电子商务网站,里面每一个博客或者商家都可以理解为一个小的网站,他们是如何做到的呢,如何实现同样的核心代码,不同的用户用有不同的效果,实现类型的网站得到复用而不是复制相同的代码呢?
            那些博客网站、电子商务网站是利用用户ID的不同,来区别不同的用户,具体的数据和模板可以不同,但代码核心和数据库却是共享的。
     
             假如很多项目到来时,他们需要的网站结构相似度很高,而且都不是那种高访问量的网站,如果分成多个虚拟空间来处理,相当于一个相同网站的实例对象很多,这是造成服务器的大量资源浪费,当然更实际的其实是钞票的浪费,如果整合到一个网站中,共享其相关的代码和数据,那么对于硬盘、内存、CPU、数据库空间等服务器资源都可以达到共享,减少服务器资源,而对于代码,由于是一份实例,维护和扩展都更加容易。
     
            好像很不错的样子,我也这么觉得,那我们就一起来了解一下, 如何做到共享一份实例吧。
     
    2、定义:
    享元模式(Flyweight),运用共享技术有效地支持大量细粒度的对象。
    3、UML(结构图)
    类解析:
    • FlyWeightFactory:一个共享工厂,用来创建并管理Flyweight对象。它主要是用来确保合理地共享Flyweight,当用户请求一个Flyweight是,FlyweightFactory对象提供一个已创建得实例或者创建一个(如果不存在的话)
    • Flyweight:所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态,
    • ConcreteFlyweight:继承Flyweight超类或实现Flyweight接口,并为内部状态增加存储空间
    • UnsharedConcreteFlyweight:指那些不需要共享的Flyweight。因为Flyweight接口共享成为可能,但它不强制要求共享。
    4、实践
            网站共享代码
    package com.zcr.flyweight;
    //享元设计模式实现
    //网站抽象类
    public abstract class WebSite
    {
     public abstract void Use();
    }
    package com.zcr.flyweight;
    //具体的网站类
    public class ConcreteWebSite extends WebSite
    {
     private String name = "";
     
     public ConcreteWebSite(String name)
     {
      this.name = name;
     }
     
     @Override
     public void Use()
     {
      System.out.println("网站分类:"+name);
     }
    }
    package com.zcr.flyweight;
    import java.util.Hashtable;
    //网站工厂
    public class WebsiteFactory
    {
     private Hashtable<String,WebSite> flyweights = new Hashtable<String, WebSite>();
     
     //获得网站分类
     public WebSite GetWebSiteCategory(String key)
     {
      //判断是否存在这个对象,如果存在则直接返回,若不存在,则实例化它再返回
      if(!flyweights.contains(key))
      {
       flyweights.put(key, new ConcreteWebSite(key));
      }
      return flyweights.get(key);
     }
     
     //获取网站分类的总数
     public int GetWebSiteCount()
     {
      return flyweights.size();
     }
    }
    package com.zcr.flyweight;
    public class FlyweightTest
    {
     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();
     
      System.out.println("网站分类总数为:" + f.GetWebSiteCount());
     }
    }

    结果:

     

      上面只实现了对象的共享,不管建立几个网站,是要是‘产品展示’都好是一样的的,只要是‘博客’也是完全相同的,但这样是有问题的,你给企业建立的网站不是一家企业,它们的数据不会相同,所以至少它们应该有不同的账号,那我们该怎么办呢?
     
    概念:
    内部状态:在享元内部并且不会随环境改变而改变的共享部分
    外部状态:随环境改变而改变的、不可能共享的状态就是外部状态
     
            享元模式可以避免大量非常相似类的开销,在程序设计中,有时需哟生成大量细粒度的类实例来表示数据,如果能发现这些实例除了几个参数外基本上都是相同的,有时就能够大幅度的减少需要实例化类的数量。如果能把那些参数移到类实例的外面,在方法调用时将它们传进来,就可以通过共享大幅度地减少单个实例的数目。也就是说,享元模式Flyweight执行时所需要的状态有内部的也有外部的,内部状态存储于ConcreteFlyweight对象之中,而外部对象则应该考虑由客户端对象存储或计算,当调用Flyweight对象的操作时,将该状态传递给它。
     
    应用场景
    如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时就应该考虑使用;还有就是对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。
            java的String就是采用了这种方式。
     
    package com.zcr.flyweight2;
    
    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;
        }
        
        
    }
    package com.zcr.flyweight2;
    
    //享元设计模式实现
    
    //网站抽象类
    public abstract class WebSite
    {
        //“使用”方法需要传递“用户”对象
        public abstract void Use(User user);
    }
    package com.zcr.flyweight2;
    
    //具体的网站类
    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());
    
        }
    
    }
    package com.zcr.flyweight2;
    
    import java.util.Hashtable;
    
    //网站工厂
    public class WebsiteFactory
    {
        private Hashtable<String,WebSite> flyweights = new Hashtable<String, WebSite>();
        
        //获得网站分类
        public WebSite GetWebSiteCategory(String key)
        {
            //判断是否存在这个对象,如果存在则直接返回,若不存在,则实例化它再返回
            if(!flyweights.contains(key))
            {
                flyweights.put(key, new ConcreteWebSite(key));
            }
            return flyweights.get(key);
        }
        
        //获取网站分类的总数
        public int GetWebSiteCount()
        {
            return flyweights.size();
        }
    }
    package com.zcr.flyweight2;
    
    public class FlyweightTest
    {
        public static void main(String[] args)
        {
            WebsiteFactory f = new WebsiteFactory();
            
            WebSite fx = f.GetWebSiteCategory("产品展示");
            fx.Use(new User("小菜"));
            
            WebSite fy = f.GetWebSiteCategory("产品展示");
            fy.Use(new User("大烟笼"));
            
            WebSite fz = f.GetWebSiteCategory("产品展示");
            fz.Use(new User("大菜"));
            
            WebSite fl = f.GetWebSiteCategory("博客");
            fl.Use(new User("老顽童"));
            
            WebSite fm = f.GetWebSiteCategory("博客");
            fm.Use(new User("肥菜"));
            
            WebSite fn = f.GetWebSiteCategory("博客");
            fn.Use(new User("小小斌"));
            
            System.out.println("网站分类总数为:" + f.GetWebSiteCount());
        }
    }

     结果:

  • 相关阅读:
    spring @Primary-在spring中的使用(十九)
    Java中lombok @Builder注解使用详解(十八)
    Spring Boot的MyBatis注解:@MapperScan和@Mapper(十七)
    js基础只是总结-语句
    js基础知识-数据类型
    启动redis服务报错Creating Server TCP listening socket *:6379: bind: Address already in use [duplicate]
    gitlab 配置SSH和ACCESS TOKEN
    https nginx配置
    Vue和React区别
    深入虚拟DOM和DOM-diff
  • 原文地址:https://www.cnblogs.com/0201zcr/p/4612345.html
Copyright © 2020-2023  润新知