博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
享元模式(Flyweight)解析例子
阅读量:6535 次
发布时间:2019-06-24

本文共 3319 字,大约阅读时间需要 11 分钟。

摘要:本文深入浅出的讲述了设计模式中的享元模式
,
并给出了简单的示例
,
例子浅显易懂
,
并附带源代码。
       
享元
模式属于结构型模式,其意图是运用共享技术有效地支持大量细粒度的对象。有些应用程序得益于在其整个设计过程中采用面向对象技术,但是简单化的实现代价极大。flyweight
是一个共享对象,它可以同时在多个场景中使用,并且每个场景中Flyweight
队作为一个独立的对象,这一点与非共享对象的实例没有区别,Flyweight
不能对他所运行的场景作出任何假设,这里的关键概念是内部状态和外部状态之间的区别。内部状态存储于Flyweight
中,它包含了独立Flyweight
场景的信息,这些信息使得Flyweight
可以被共享,而外部状态取决于 Flyweight
场景,并根据场景而变化,因此不可共享,用户对象负责在必要的时候将外部状态传递给Flyweight
Flyweight
模式对那些通常因为数量太大而难以用对象来表示的概念或者实体建立模型。
       
适用性:Flyweight
模式的有效性很大程度上取决于如何使用它以及在何处使用它,当以下情况都成立时使用Flyweight
模式。
l         
一个应用程序使用了大量的对象,
l         
完全有余使用了大量的对象,造成了很大的存储开销。
l         
对象的大多数状态都可以变为外部状态。
l         
如果删除对象的外部状态那么可以用相对较少的共享对象取代很多组对象。
l         
应用程序不依赖于对象标识,由于Flyweight
对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。
1
 
参与者:       
       Flyweight:
描述一个接口,通过这个接口 flyweight
可以接受并作用于外部状态。
       ConcreteFlyweight(MyImage)
:实现 flyweight
接口,并为内部状态增加存储空间。 ConcreteFlyweight
对象必须是可以共享的,它所存储的状态必须是内部的。即:它必须独立于 ConcreteFlyweight
对象的场景 .
UnsharedConcreteFlyweight:
并非所有的 Flyweight
子类都需要被共享。 Flyweight
接口使共享成为可能,但它并不强制共享,在 Flyweight
对象结构的某些层次, UnsharedConcreteFlyweight 
对象通常将 ConcreteFlyweight
对象作为子节点。
FlyweightFactory(MyImageFactory)
:创建并管理 Flyweight
对象。确保合理的共享 Flyweight
。当用户请求一个 flyweight
时, FlyweightFactory
对象提供一个已经创建的实例或者创建一个。
Client
:维持一个对 Flyweight
的引用。计算或者存储一个(多个) flyweight
的外部状态。 Flyweight
执行时所需要的状态必定是内部的或者外部的状态,内部状态存储于 ConcreteFlyweight
对象中,而外部对象则由 Client
对象存储或计算,当用户调用 flyweight
对象的操作时,将该状态传递给他。用户不应直接对 ConcreteFlyweight
类进行实例化,而只能从 FlyweightFactory
对象得到 ConcreteFlyweight
对象,这可以保证对他们适当的进行共享。
本人认为 Flyweight
模式的核心就是把大量共享的对象收集在一起使用简单工厂模式进行管理,避免由于大量的小对象导致系统的内存过渡消耗。下面是一个简单的例子,例子不是很好,并不能显示 Flyweight
模式的所有特征。
客户端需要图片,从 MyImageFactory
中取得,如果 MyImageFactory
存储的 Image
中没有需要的图片 ,
便创建一个,并把创建的图片存储在保留 Flyweight
的数组中,以便于下次直接获取。
相应的代码:
MyImage
的代码:
       
package
 flyweight;
import
 java.awt.*;
import
 java.awt.image.*;
import
 java.io.*;
public
 
class
 MyImage{
    
private
 Image 
image
;
    
public
 MyImage(String file){
       Toolkit toolkit = Toolkit.getDefaultToolkit();  
       File f = 
new
 File(file);
       
if
(f.exists()){
           
image
 = toolkit.getImage(file);
       }
       
else
{
           System.
out
.println(
"File unable to load!"
);
       }
    }
    
public
 
void
 draw(Graphics g,
int
 x,
int
 y,String name,ImageObserver obs){
       
g.drawImage(
image
,x,y,30,30,obs);
       
g.drawString(name,x,y+40);
    }
}
MyImageFactory
的代码:
package
 flyweight;
public
 
class
 MyImageFactory{
    MyImage[] 
images
;
    
public
 MyImageFactory(){
       
images
 = 
new
 MyImage[3];
       
for
(
int
 i=0;i<3;i++)
           
images
[i]= 
new
 MyImage(
"flyweight/lili"
+i+
".gif"
);
    }
    
public
 MyImage getMyImage(
int
 i){
       
return
 
images
[i];
    }
}
 
 
Client
代码:
package flyweight;
import javax.swing.*;
import java.awt.*;
public class Client extends JFrame{
       private MyImageFactory factory;
       private String[] names;
       public Client(){
              super("Flyweight sample");
              factory = new MyImageFactory();
              setSize(220,300);
              setVisible(true);
              repaint();
              names = new String[]{"pig","dog","cat"};
       }
       public void resize(){
              repaint();
       }
       public void paint(Graphics g){
              g.clearRect(0,0,getWidth(),getHeight());
              String name;
              for(int i=0;i<5;i++){
                     for(int j=0;j<5;j++){
                            int number=(int)(Math.random()*3%3);
                            MyImage myImage = factory.getMyImage(number);
                            number=(int)(Math.random()*3%3);
                            name = names[number];
                            myImage.draw(g,10+i*40,45+j*45,name,this);
                     }
              }
       }
       public static void main(String[] args){
              new Client();
       }
}
总结: Flyweight
的目标是尽量减少大量可以被共享的对象的数目,并把可变的与不可变得状态使用内部状态 (Flyweight)
与外部状态区分开来。
本文转自凌辉博客51CTO博客,原文链接http://blog.51cto.com/tianli/37118如需转载请自行联系原作者
lili00okok
你可能感兴趣的文章
Makefile 中:= ?= += =的区别【转】
查看>>
使用makecontext实现用户线程【转】
查看>>
Comet:基于 HTTP 长连接的“服务器推”技术
查看>>
BZOJ 2733: [HNOI2012]永无乡 启发式合并treap
查看>>
四种方法校验数组中是否包含某个指定的字符串
查看>>
29、Java并发性和多线程-非阻塞算法
查看>>
安装OpenResty开发环境
查看>>
第0课 从0开始
查看>>
hadoop无法启动DataNode问题
查看>>
java泛型中<?>和<T>区别
查看>>
这里是指推送通知跟NSNotification有区别:
查看>>
Linux中断(interrupt)子系统之一:中断系统基本原理【转】
查看>>
用户ID的代码生成
查看>>
win7经常出现“关闭xxxx前您必须关闭所有会话框”
查看>>
SNMP安全配置的两种方法(也可同一时候兼顾配置两种方法)
查看>>
react-native 常见操作 及 git 补充
查看>>
MongoDB 自己定义函数
查看>>
Summary Day30
查看>>
逆向输出回环数组
查看>>
自己动手,实现“你的名字”滤镜
查看>>