秒懂设计模式--学习笔记(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.coloradmin.cn/o/1937069.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!