>  기사  >  Java  >  플라이웨이트 모드 샘플 코드(그림 및 텍스트)에 대한 심층적인 이해

플라이웨이트 모드 샘플 코드(그림 및 텍스트)에 대한 심층적인 이해

黄舟
黄舟원래의
2017-03-14 10:22:241092검색


요약:

 객체 지향 기술은 유연성이나 확장성 문제를 일부 해결할 수 있습니다. 그러나 대부분의 경우 시스템의 클래스와 개체 수를 늘려야 합니다. 객체가 너무 많으면 운영 비용이 너무 높아 성능 저하 및 기타 문제가 발생합니다. 플라이웨이트 모드공유 기술을 사용하여 동일하거나 유사한 개체를 재사용하여 시스템 리소스 활용도를 높입니다. 이 글에서는 먼저 플라이웨이트 모델이 해결해야 할 문제와 문제 해결의 개념을 설명한 후, 구현 관점에서 모델의 본질에 초점을 맞추고, 더 나아가 모델이 포함하는 역할과 조직 구조를 제시합니다. 마지막으로 공유 모드의 적용 사례와 사용 시나리오를 제공합니다.


1. 동기 부여

 객체 지향 기술은 어느 정도 유연성이나 확장성 문제를 잘 해결할 수 있지만 시스템에 구현해야 하는 경우가 많습니다. 클래스와 객체의 수. 객체가 너무 많으면 운영 비용이 너무 높아 성능 저하 및 기타 문제가 발생합니다. 이러한 문제를 해결하기 위해 플라이급 모델이 탄생했습니다. Flyweight 모드는 공유 기술을 통해 동일하거나 유사한 객체의 재사용을 실현합니다. 개략도는 다음과 같습니다(문자열 “Hello world”가 포함된 Hello world 객체를 공유할 수 있음). 내부 상태 , 공유 가능, 글꼴 색상은 외부 상태, 공유 불가능, 클라이언트에 의해 설정됨):

   플라이웨이트 모드 샘플 코드(그림 및 텍스트)에 대한 심층적인 이해

플라이웨이트 모드에서 공유할 수 있는 것과 동일한 콘텐츠를 내부 상태(Intrinsic State)라고 하고, 외부 환경에서 설정해야 해서 공유할 수 없는 콘텐츠를 이라고 합니다. 🎜>외부 상태(Extrinsic State), 여기서 외부 상태와 내부 상태는 서로 독립적이며, 외부 상태의 변화가 내부 상태의 변화를 일으키지 않습니다. 내부 상태와 외부 상태의 구별로 인해 동일한 객체라도 외부 상태를 다르게 설정하여 다른 특성을 가질 수 있으며, 동일한 내부 상태를 공유할 수 있습니다. 즉, 플라이웨이트 모드의 본질은 분리와 공유입니다. 분리는 변해도 변하지 않고, 공유도 변하지 않습니다.

객체의 상태를 내부 상태와 외부 상태로 나누고, 변하지 않은 부분을 공유함으로써 객체 수를 줄이고 메모리를 절약하는 목적을 달성합니다. .

플라이웨이트 모드에서는 일반적으로 팩토리 모드가 나타납니다. 플라이웨이트 풀(동일한 내부 상태로 플라이웨이트를 저장하는 데 사용됨)을 유지하려면 플라이웨이트 팩토리를 만들어야 합니다. 플라이웨이트 모드에서 공유되는 것은 플라이웨이트 객체의 내부 상태이며, 외부 상태는 환경을 통해 설정되어야 합니다. 실제 사용 시 공유할 수 있는 내부 상태는 제한되어 있으므로 플라이웨이트 객체는 일반적으로 내부 상태가 적은 작은 객체로 설계됩니다. 이러한 객체를 Fine-grained Object라고도 합니다.
. 플라이웨이트 모드의 목적은 공유 기술을 사용하여 수많은 미세한 개체를 재사용하는 것입니다.


2. 정의 및 구조

플라이웨이트 패턴: 공유 기술을 사용하여 수많은 세분화된 개체의 재사용을 효과적으로 지원합니다. 시스템은 소수의 객체만 사용하며 이러한 객체는 매우 유사하고 상태 변화가 매우 작기 때문에 객체를 여러 번 재사용할 수 있습니다. 플라이웨이트 모드에서는 공유할 수 있는 객체가 세분화된 객체여야 하므로 경량 모드라고도 합니다. 객체 구조 모드입니다.

플라이웨이트 패턴: 공유를 사용하여 다수의 세분화된 객체


를 효율적으로 지원합니다.

1. 모드에 참여하는 캐릭터

 플라이웨이트: 플라이웨이트 인터페이스 , 이를 통해 외부 상태가 전달되고 작동됩니다.
ConcreteFlyweight: 특정 플라이웨이트 구현 객체는 공유 가능해야 합니다. 플라이급 개체의 내부 상태를 캡슐화해야 합니다.
 UnsharedConcreteFlyweight: 비공유 플라이급 구현 개체, 모든 플라이급 개체를 공유할 수 있는 것은 아니며, 공유되지 않은 플라이급 개체는 일반적으로 플라이급 개체의 조합입니다. >
FlyweightFactory: 플라이웨이트 팩토리는 주로 공유 플라이웨이트 개체를 생성 및 관리하고 공유 플라이웨이트 개체에 액세스하기 위한 외부 인터페이스를 제공하는 데 사용됩니다.

2.

3. 모드 확장Flyweight Structure.png-72.6kB


간단한 플라이웨이트 모드 : 순수 플라이웨이트 모드에서는 모든 플라이웨이트 객체, 즉 모든 하위 클래스가 공유 가능합니다. 추상 플라이급 클래스는 공유될 수 있으며, 공유되지 않는 구체적인 플라이급 클래스는 없습니다.

       
  • 구현예 :

    플라이웨이트 모드 샘플 코드(그림 및 텍스트)에 대한 심층적인 이해

    //抽象享元角色类public interface Flyweight {
        //一个示意性方法,参数state是外蕴状态
        public void operation(String state);
    }//具体享元角色类//具体享元角色类ConcreteFlyweight有一个内蕴状态,在本例中一个Character类型的intrinsicState属性代表,它的值应当在享元对象
    //被创建时赋予。所有的内蕴状态在对象创建之后,就不会再改变了。如果一个享元对象有外蕴状态的话,所有的外部状态都必须存储在客户端,
    //在使用享元对象时,再由客户端传入享元对象。这里只有一个外蕴状态,operation()方法的参数state就是由外部传入的外蕴状态。
    public class ConcreteFlyweight implements Flyweight {
        private Character intrinsicState = null;    /**
         * 构造函数,内蕴状态作为参数传入
         * @param state
         */
        public ConcreteFlyweight(Character state){        this.intrinsicState = state;
        }    /**
         * 外蕴状态作为参数传入方法中,改变方法的行为,
         * 但是并不改变对象的内蕴状态。
         */
        @Override
        public void operation(String state) {        // TODO Auto-generated method stub
            System.out.println("Intrinsic State = " + this.intrinsicState);
            System.out.println("Extrinsic State = " + state);
        }
    
    }//享元工厂角色类//享元工厂角色类,必须指出的是,客户端不可以直接将具体享元类实例化,而必须通过一个工厂对象,利用一个factory()方法得到享元对象。
    //一般而言,享元工厂对象在整个系统中只有一个,因此也可以使用单例模式。
    //当客户端需要单纯享元对象的时候,需要调用享元工厂的factory()方法,并传入所需的单纯享元对象的内蕴状态,由工厂方法产生所需要的//享元对象。
    public class FlyweightFactory {
        private Map<Character,Flyweight> files = new HashMap<Character,Flyweight>();    
        public Flyweight factory(Character state){        
        //先从缓存中查找对象
            Flyweight fly = files.get(state);        
            if(fly == null){            
            //如果对象不存在则创建一个新的Flyweight对象
                fly = new ConcreteFlyweight(state);            
                //把这个新的Flyweight对象添加到缓存中
                files.put(state, fly);
            }        return fly;
        }
    }//客户端类public class Client {
    
        public static void main(String[] args) {        // TODO Auto-generated method stub
            FlyweightFactory factory = new FlyweightFactory();
            Flyweight fly = factory.factory(new Character(&#39;a&#39;));
            fly.operation("First Call");
    
            fly = factory.factory(new Character(&#39;b&#39;));
            fly.operation("Second Call");
    
            fly = factory.factory(new Character(&#39;a&#39;));
            fly.operation("Third Call");
        }
    
    }

    클라이언트가 플라이웨이트 객체 3개를 신청했지만 실제로 생성된 플라이웨이트 객체는 2개뿐이다. 공유가 무엇을 의미하는지.
  • 실행 결과는 다음과 같습니다.

   

플라이웨이트 모드 샘플 코드(그림 및 텍스트)에 대한 심층적인 이해

복합 플라이웨이트 모드:
콤비네이션 모드 이들을 결합하면 복합 플라이웨이트 객체가 형성될 수 있습니다. 이러한 복합 플라이웨이트 객체 자체는 공유할 수 없지만 간단한 플라이웨이트 객체로 분해할 수 있으며, 후자는 공유할 수 있습니다.
  •     

    플라이웨이트 모드 샘플 코드(그림 및 텍스트)에 대한 심층적인 이해 구현 예:

    //抽象享元角色类public interface Flyweight {
        //一个示意性方法,参数state是外蕴状态
        public void operation(String state);
    }//具体享元角色类
    //具体享元角色类ConcreteFlyweight有一个内蕴状态,在本例中一个Character类型的intrinsicState属性代表,它的值应当在享元对象
    //被创建时赋予。所有的内蕴状态在对象创建之后,就不会再改变了。如果一个享元对象有外蕴状态的话,所有的外部状态都必须存储在客户端,
    //在使用享元对象时,再由客户端传入享元对象。这里只有一个外蕴状态,operation()方法的参数state就是由外部传入的外蕴状态。
    public class ConcreteFlyweight implements Flyweight {
        private Character intrinsicState = null;    /**
         * 构造函数,内蕴状态作为参数传入
         * @param state
         */
        public ConcreteFlyweight(Character state){        this.intrinsicState = state;
        }    /**
         * 外蕴状态作为参数传入方法中,改变方法的行为,
         * 但是并不改变对象的内蕴状态。
         */
        @Override
        public void operation(String state) {        // TODO Auto-generated method stub
            System.out.println("Intrinsic State = " + this.intrinsicState);
            System.out.println("Extrinsic State = " + state);
        }
    
    }
    //复合享元角色类
    //复合享元对象是由单纯享元对象通过复合而成的,因此它提供了add()这样的聚集管理方法。由于一个复合享元对象具有不同的聚集元素,
    //这些聚集元素在复合享元对象被创建之后加入,这本身就意味着复合享元对象的状态是会改变的,因此复合享元对象是不能共享的。
    //复合享元角色实现了抽象享元角色所规定的接口,也就是operation()方法,这个方法有一个参数,代表复合享元对象的外蕴状态。
    //一个复合享元对象的所有单纯享元对象元素的外蕴状态都是与复合享元对象的外蕴状态相等的;
    //而一个复合享元对象所含有的单纯享元对象的内蕴状态一般是不相等的,不然就没有使用价值了。
    public class ConcreteCompositeFlyweight implements Flyweight {
    
        private Map<Character,Flyweight> files = new HashMap<Character,Flyweight>();    /**
         * 增加一个新的单纯享元对象到聚集中
         */
        public void add(Character key , Flyweight fly){
            files.put(key,fly);
        }    /**
         * 外蕴状态作为参数传入到方法中
         */
        @Override
        public void operation(String state) {
            Flyweight fly = null;        for(Object o : files.keySet()){
                fly = files.get(o);
                fly.operation(state);
            }
    
        }
    
    }//享元工厂角色类//享元工厂角色提供两种不同的方法,一种用于提供单纯享元对象,另一种用于提供复合享元对象。public class FlyweightFactory {
        private Map<Character,Flyweight> files = new HashMap<Character,Flyweight>();    /**
         * 复合享元工厂方法
         */
        public Flyweight factory(List<Character> compositeState){
            ConcreteCompositeFlyweight compositeFly = new ConcreteCompositeFlyweight();        for(Character state : compositeState){
                compositeFly.add(state,this.factory(state));
            }        return compositeFly;
        }    /**
         * 单纯享元工厂方法
         */
        public Flyweight factory(Character state){        //先从缓存中查找对象
            Flyweight fly = files.get(state);        if(fly == null){            //如果对象不存在则创建一个新的Flyweight对象
                fly = new ConcreteFlyweight(state);            //把这个新的Flyweight对象添加到缓存中
                files.put(state, fly);
            }        return fly;
        }
    }//客户端类public class Client {
    
        public static void main(String[] args) {
            List<Character> compositeState = new ArrayList<Character>();
            compositeState.add(&#39;a&#39;);
            compositeState.add(&#39;b&#39;);
            compositeState.add(&#39;c&#39;);
            compositeState.add(&#39;a&#39;);
            compositeState.add(&#39;b&#39;);
    
            FlyweightFactory flyFactory = new FlyweightFactory();
            Flyweight compositeFly1 = flyFactory.factory(compositeState);
            Flyweight compositeFly2 = flyFactory.factory(compositeState);
            compositeFly1.operation("Composite Call");
    
            System.out.println("---------------------------------");        
            System.out.println("复合享元模式是否可以共享对象:" + (compositeFly1 == compositeFly2));
    
            Character state = &#39;a&#39;;
            Flyweight fly1 = flyFactory.factory(state);
            Flyweight fly2 = flyFactory.factory(state);
            System.out.println("单纯享元模式是否可以共享对象:" + (fly1 == fly2));
        }
    }
  • 실행 결과는 다음과 같습니다.

    다른 모드와 함께 플라이웨이트 모드 사용

    플라이웨이트 모드 샘플 코드(그림 및 텍스트)에 대한 심층적인 이해 플라이웨이트 모드의 플라이웨이트 팩토리 클래스에서는 일반적으로 플라이웨이트 객체 반환에 대해

    정적
    팩토리 메소드가 제공됩니다.
    • 플라이웨이트 객체를 생성하는 간단한 팩토리 패턴

      시스템에는 일반적으로 플라이웨이트 팩토리가 하나만 있으므로 플라이웨이트 팩토리 클래스를 설계할 수 있습니다. 싱글톤 모드 사용; 

      플라이웨이트 모드는 조합 모드와 결합하여 복합 플라이웨이트 모드를 형성할 수 있으며, 플라이웨이트 객체의 외부 상태를 균일하게 설정합니다.

      3. 패턴 분석 플라이웨이트 모드는 시스템 성능을 고려한

      모드입니다. > 플라이웨이트 모드를 사용하면 메모리 공간을 절약하고 시스템 성능을 향상시킬 수 있습니다.

     

    플라이웨이트 모델의 핵심은 플라이웨이트 팩토리 클래스입니다. 플라이웨이트 팩토리 클래스의 기능은 플라이웨이트 개체를 저장하기 위한 플라이웨이트 풀을 제공하는 것입니다. 개체가 필요하면 먼저 플라이급 풀에서 가져옵니다. 플라이급 풀에 개체가 없으면 새 플라이급 개체가 생성되어 사용자에게 반환되고 개체가 플라이급 풀. 일반적인 플라이웨이트 팩토리 클래스 코드:

    public class FlyweightFactory{
        private HashMap flyweights = new HashMap();    public Flyweight getFlyweight(String key)
        {        if(flyweights.containsKey(key))
            {            return (Flyweight)flyweights.get(key);
            }        else
            {
                Flyweight fw = new ConcreteFlyweight();
                flyweights.put(key,fw);            return fw;
            }
        }
    }

    플라이웨이트 모드는 공유 방식으로 많은 수의 세분화된 개체를 효율적으로 지원합니다. 핵심 메타 객체 공유를 활성화하는 것은 내부 상태와 외부 상태를 구별하는 것입니다. 위치:

    내부 상태

    는 플라이웨이트 객체 내부에 저장된 상태이며 환경에 따라 변경되지 않으므로 내부 상태를 공유할 수 있습니다. .

    외부 상태
      는 환경에 따라 변하며 공유할 수 없는 상태입니다. 플라이웨이트 개체의 외부 상태는 클라이언트에 의해 저장되어야 하며 플라이웨이트 개체가 생성된 후 필요할 때 플라이웨이트 개체로 전달되어야 합니다. 하나의 외부 상태는 다른 외부 상태와 독립적입니다.
    • 일반적인 플라이급 코드:

      public class Flyweight{
              //内部状态作为成员属性
          private String intrinsicState;    public Flyweight(String intrinsicState)
          {        this.intrinsicState = intrinsicState;
          }    public void operation(String extrinsicState)
          {
              ......
          }   
      }

      四. 模式的应用

      • 享元模式在编辑器软件中大量使用,如在一个文档中多次出现相同的图片,则只需要创建一个图片对象,通过在应用程序中设置该图片出现的位置,可以实现该图片在不同地方多次重复显示。

      • 广义上讲,在JDK类库中定义的String类也是使用享元模式的典型。

      public class Demo{
          public static void main(String args[])
          {
              String str1 = "abcd";
              String str2 = "abcd";
              String str3 = "ab" + "cd";
              String str4 = "ab";
              str4 += "cd";
              System.out.println(str1 == str2);      //true
              System.out.println(str1 == str3);      //true
              System.out.println(str1 == str4);      //false
          }
      }

      五. 总结

      1、模式适用环境
        
      在以下情况下可以使用享元模式:

      • 一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费;

      • 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中(细粒度对象);

      • 使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。


      2、模式的优点

        (1)它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份;
        (2)享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。


      3、模式的缺点

        (1)享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化;
        (2)为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。


      4、模式的实现

      • 享元模式运用共享技术有效地支持大量 细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用,它是一种对象结构型模式。

      • 享元模式包含四个角色:抽象享元类声明一个接口,通过它可以接受并作用于外部状态;具体享元类实现了抽象享元接口,其实例称为享元对象;非共享具体享元是不能被共享的抽象享元类的子类;享元工厂类用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中。

      • 享元模式以共享的方式高效地支持大量的细粒度对象,享元对象能做到共享的关键是区分内部状态和外部状态。其中内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,因此内部状态可以共享;外部状态是随环境改变而改变的、不可以共享的状态。

    위 내용은 플라이웨이트 모드 샘플 코드(그림 및 텍스트)에 대한 심층적인 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    성명:
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.