• 享元模式(Flyweight)---结构型


    1 基础知识

    定义:提供了减少对象数量从而改善应用所需的对象结构的方式。特征:运用共享技术有效支持大量细粒度的对象。

    本质:分离与共享。

    使用场景:

    (1)如果一个应用程序使用了大量的细粒度对象,可以使用享元模式来减少对象数量。如果由于使用大量的对象,造成很大的存储开销,可以使用享元模式来减少对象数量,并节约内存。

    (2)如果对象的大多数状态都可以转变为外部状态,比如通过计算得到,或是从外部传入等,可以使用享元模式来实现内部状态和外部状态的分离。

    (3)如果不考虑对象的外部状态,可以用相对较少的共享对象取代很多组合对象,可以使用享元模式来共享对象,然后组合对象来使用这些共享对象。

    优点:大大减少对象的创建,降低系统的内存,使效率提高;减少内存之外其他资源占用。缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱;可能有线程安全问题;维护共享对象,需要额外开销。

    注:并不是所有的对象都适合存,因为存的是对象的实例,实例里面存放的主要是对象属性的值。因此,如果被缓存的对象的属性值经常变动那就不适合缓存了,因为真实对象的属性值变化了,那么缓存中的对象也必须要跟着变化,否则缓存中的数据就跟真实对象的数据不同步,可以说是错误的数据了。

        因此,需要分离出被缓存对象实例中,哪些数据是不变且重复出现的,哪些数据是经常变化的,真正应该被缓存的数据是那些不变且重复出现的数据,把它们称为对象的内部状态,而那些变化的数据就不缦存了,把它们称为对象的外部状态。这样在实现的时候,把内部状态分离出来共享,称之为享元,通过共享享元对象来减少对内存的占用。把外部状态分离出来,放到外部,让应用在使用的时候进行维护,并在需要的时候传递给享元对象使用。为了控制对内部状态的共享,并且让外部能简单地使用共享数据,提供一个工厂来管理享元,把它称为享元工厂

     2 代码示例

    场景:假设公司年底要做报告,需要经理多次随机的报告。

    员工接口:

    public interface Employee {
        void report();
    }

     经理类 Manager :实现员工接口

    public class Manager implements Employee {
        @Override
        public void report() {
            System.out.println(reportContent);
        }
        private String title = "部门经理";
        //部门
        private String department;
        //报告内容
        private String reportContent;
        
        //set方式注入对象
        public void setReportContent(String reportContent) {
            this.reportContent = reportContent;
        }
    
        public Manager(String department) {
            this.department = department;
        }   
    }

    员工工厂:EmployeeFactory 创建部门经理和报告内容

    public class EmployeeFactory {
    private static final Map<String,Employee> EMPLOYEE_MAP = new HashMap<String,Employee>(); public static Employee getManager(String department){ //从部门中获取经理 Manager manager = (Manager) EMPLOYEE_MAP.get(department); if(manager == null){ //没有取到经理则创建经理 manager = new Manager(department); System.out.print("创建部门经理:"+department); //创建报告 String reportContent = department+"部门汇报:此次报告的主要内容是......"; manager.setReportContent(reportContent); System.out.println(" 创建报告:"+reportContent); //放入对象池中,下次便可以直接从其中取出了 EMPLOYEE_MAP.put(department,manager); } return manager; } }

    应用层:

    public class Test {
        //部门数组
        private static final String departments[] = {"RD","QA","PM","BD"};
    
        public static void main(String[] args) {
            for(int i=0; i<10; i++){
                //随机指定部门
                String department = departments[(int)(Math.random() * departments.length)];
                Manager manager = (Manager) EmployeeFactory.getManager(department);
                manager.report();
            }
        }
    }

     外部状态:在经理类中的department属性便是外部状态,是会随机发生变化的。内部状态:经理类中的title属性便是内部状态,无论怎么变都不会发生变化,这里是title在程序中并没有应用到只是作为分析的。

     3 相关模式

    (1)享元模式与单例模式

     这两个模式可以组合使用。通常情况下,享元模式中的享元工厂可以实现成为单例。另外,享元工厂中缓存的享元对象,都是单实例的,可以看成是单例模式的一种变形控制,在享元工厂中来单例享元对象。

    (2)享元模式与组合模式

    这两个模式可以组合使用。在享元模式中,存在不需要共享的享元实现,这些不需要共享的享元通常是对共享的享元对象的组合对象。也就是说,享元模式通常会和组合模式组合使用,来实现更复杂的对象层次结构。

    (3)享元模式与状态模式

    这两个模式可以组合使用。可以使用享元模式来共享状态模式中的状态对象。通常在状态模式中,会存在数量很大的、细粒度的状态对象,而且它们基本上都是可以重复使用的,都是用来处理某一个固定的状态的,它们需要的数据通常都是由上下文传入,也就是变化部分都分离出去了,所以可以用享元模式来实现这些状态对象。

    (4)享元模式与策略模式

    这两个模式可以组合使用。可以使用享元模式来实现策略模式中的策略对象。和状态模式一样,在策略模式中也存在大量细粒度的策略对象,它们需要的数据同样是从上下文传入的,所以可以使用享元模式来实现这些策略对象。

    0

  • 相关阅读:
    php利用__callStatic静态调用同类中非静态方法
    Using $this when not in object context错误原因及解决办法
    fastadmin权限修改
    call_user_func()
    php empty()奇怪现象
    LF will be replaced by CRLF in vendor/
    git放弃本地,强制拉取远程
    tp5防xss攻击方法
    php curl
    关于Mac设置alias别名访问服务器
  • 原文地址:https://www.cnblogs.com/youngao/p/11350592.html
Copyright © 2020-2023  润新知