秒懂设计模式--学习笔记(11)【结构型-享元模式】
目录 10、享元模式 10.1 享元模式 10.2 举例 10.2.1 马赛克 10.2.2 游戏地图(以草原地图作为范例) 10.3 总结
10、享元模式
10.1 享元模式
“享元”则是共享元件 的意思 享元模式的英文flyweight是轻量级的意思,这就意味着享元模式能使程序变得更加轻量化 当系统存在大量的对象,并且这些对象又具有相同的内部状态时,我们就可以用享元模式共享相同的元件对象 ,以避免对象泛滥造成资源浪费。 测试类结构
10.2 举例
10.2.1 马赛克
虽然马赛克小块数量比较多,但经过观察我们会发现, 分析组成,进行归类 后,找到元件 只有4种:黑色块、灰色块、灰白色块以及白色块。 我们可以说,这就是4个“元”色块
10.2.2 游戏地图(以草原地图作为范例)
对组成部分进行归类分析,找到原件 游戏地图都是由一个个小的单元图块组成的 其中除房屋比较大之外,其他图块的尺寸都一样,它们分别为河流、草地、道路,这些图块便是4个元图块 分析建模 定义一个图块类来描述图块,具体属性应该包括“图片”和“位置”信息,并且具备按照这些信息去绘制图块的能力:Segment package flyweight ;
public class Segment { private String image; private int x, y; public Segment ( String image, int x, int y) { this . image = image; System . out. println ( "从磁盘加载[" + image + "]图片……" ) ; this . x = x; this . y = y; } public void draw ( ) { System . out. println ( "在位置[" + x + ":" + y + "]上绘制图片:[" + image + "]" ) ; }
}
在地图第一行随便绘制一些图块,Client.test1() 在这一步会发现,图片加载很慢,一张图片加载要半秒,10张图块就要耗费5秒,影响用户体验 package flyweight ;
public class Client { private static void test1 ( ) { new Segment ( "河流" , 10 , 10 ) . draw ( ) ; new Segment ( "河流" , 10 , 20 ) . draw ( ) ; new Segment ( "道路" , 10 , 30 ) . draw ( ) ; new Segment ( "草地" , 10 , 40 ) . draw ( ) ; new Segment ( "草地" , 10 , 50 ) . draw ( ) ; new Segment ( "草地" , 10 , 60 ) . draw ( ) ; new Segment ( "草地" , 10 , 70 ) . draw ( ) ; new Segment ( "草地" , 10 , 80 ) . draw ( ) ; new Segment ( "道路" , 10 , 90 ) . draw ( ) ; new Segment ( "道路" , 10 , 100 ) . draw ( ) ; }
}
图片与坐标状态初始化后就固定下来了,简单讲就是被绘制出来后就不必变动了,即使要变也是将拼好的地图作为一个大对象整体挪动 图件共享(优化) 继续分析每个图块的坐标是不同 的,但有很大一部分图块的材质图(图片)是相同 的 于是我们可以得出结论,材质图是可以作为享元的,而坐标则不能 既然要共享相同的图片,那么我们就得将图块类按图片拆分成更细的材质类,如河流类、草地类、道路类等 而坐标不能作为图块类的享元属性,所以我们就得设法把这个属性抽离出去由外部负责 代码实战 首先需要定义一个接口,规范这些材质类的绘图标准(接口:规范标准Drawable) 当然,除了接口方式,我们还可以用抽象类抽离出更多的属性和方法,使子类变得更加简单 package flyweight ;
public interface DrawAble {
void draw ( int x, int y) ;
}
定义一系列材质类并实现此绘图接口 package flyweight. texture ;
import flyweight. DrawAble ;
public class River implements DrawAble { private String image; public River ( ) { this . image = "河流" ; System . out. print ( "从磁盘加载[" + image + "]图片,耗时……" ) ; } @Override public void draw ( int x, int y) { System . out. println ( "在位置[" + x + ":" + y + "]上绘制图片:[" + image + "]" ) ; }
}
package flyweight. texture ; import flyweight. DrawAble ; public class Grass implements DrawAble { private String image; public Grass ( ) { this . image = "草地" ; System . out. print ( "从磁盘加载[" + image + "]图片,耗时……" ) ; } @Override public void draw ( int x, int y) { System . out. println ( "在位置[" + x + ":" + y + "]上绘制图片:[" + image + "]" ) ; } }
package flyweight. texture ; import flyweight. DrawAble ; public class Road implements DrawAble { private String image; public Road ( ) { this . image = "道路" ; System . out. println ( "从磁盘加载[" + image + "]图片,耗时…" ) ; } @Override public void draw ( int x, int y) { System . out. println ( "在位置[" + x + ":" + y + "]上绘制图片:[" + image + "]" ) ; } }
package flyweight. texture ; import flyweight. DrawAble ; public class House implements DrawAble { private String image; public House ( ) { this . image = "房屋" ; System . out. print ( "从磁盘加载[" + image + "]图片,耗时……" ) ; } @Override public void draw ( int x, int y) { System . out. print ( "将图层切换到顶层……" ) ; System . out. println ( "在位置[" + x + ":" + y + "]上绘制图片:[" + image + "]" ) ; } }
“元之共享”的关键: package flyweight. factory ; import flyweight. DrawAble ; import flyweight. texture. Grass ; import flyweight. texture. House ; import flyweight. texture. River ; import flyweight. texture. Road ; import java. util. HashMap ; import java. util. Map ; public class SegmentFactory { private Map < String , DrawAble > images; public SegmentFactory ( ) { images = new HashMap < String , DrawAble > ( ) ; } public DrawAble getDrawable ( String image) { if ( ! images. containsKey ( image) ) { switch ( image) { case "河流" : images. put ( image, new River ( ) ) ; break ; case "草地" : images. put ( image, new Grass ( ) ) ; break ; case "道路" : images. put ( image, new Road ( ) ) ; break ; case "房屋" : images. put ( image, new House ( ) ) ; } } return images. get ( image) ; } }
并将各种图件对象提前放入内存中共享,如此便可以避免每次从磁盘重新加载 测试:Client.test2() private static void test2 ( ) { SegmentFactory factory = new SegmentFactory ( ) ; factory. getDrawable ( "河流" ) . draw ( 10 , 10 ) ; factory. getDrawable ( "河流" ) . draw ( 10 , 20 ) ; factory. getDrawable ( "道路" ) . draw ( 10 , 30 ) ; factory. getDrawable ( "草地" ) . draw ( 10 , 40 ) ; factory. getDrawable ( "草地" ) . draw ( 10 , 50 ) ; factory. getDrawable ( "草地" ) . draw ( 10 , 60 ) ; factory. getDrawable ( "草地" ) . draw ( 10 , 70 ) ; factory. getDrawable ( "草地" ) . draw ( 10 , 80 ) ; factory. getDrawable ( "道路" ) . draw ( 10 , 90 ) ; factory. getDrawable ( "道路" ) . draw ( 10 , 100 ) ; factory. getDrawable ( "房子" ) . draw ( 10 , 10 ) ; factory. getDrawable ( "房子" ) . draw ( 10 , 50 ) ; }
小结 相同部分可以作为享元,如在构造器中加载的,作为内部类即将共享的元数据,通常称为“内蕴状态” 不同部分不能作为享元,如在实现房中作为参数传入的属性,称为“外蕴状态”
10.3 总结
享元模式让图件对象将可共享的内蕴状态 “图片”维护起来,将外蕴状态 “坐标”抽离出去并定义于接口参数中 基于此,享元工厂便可以顺利将图件对象共享,以供外部随时使用。 享元模式的各角色定义如下 Flyweight(享元接口):所有元件的高层规范 ,声明与外蕴状态互动的接口标准。如:DrawAble。 ConcreteFlyweight(享元实现): 享元接口的元件实现类 ,自身维护着内蕴状态,且能接受并响应外蕴状态,可以有多个实现。如:河流类River、草地类Grass、道路类Road等。 一个享元对象可以被称作一个“元” FlyweightFactory(享元工厂):用来维护享元对象的工厂,负责对享元对象实例进行创建与管理,并对外提供获取享元对象的服务。SegmentFactory Client(客户端):享元的使用者,负责维护外蕴状态。Client “享元”的理念其实就是萃取事物的本质 将对象的内蕴状态与外蕴状态剥离开来,其中内蕴状态成为真正的“元”数据,而外蕴状态则被抽离出去由外部负责维护
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/380372.html
如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!