设计模式之------享元模式(Flyweight Pattern):内部状态(Instrinsic State)\外部状态(Extrinsic State)
一、概念
①、什么是享元模式?
运用共享技术有效地支持大量细粒度的对象。
②、什么是细粒度对象?享元模式的两个状态?
在分析什么是细粒度对象之前,我们现了解一下享元对象的两个状态:内部状态和外部状态。
在享元对象内部并且不用随环境改变而改变的共享部分,成为享元对象的内部状态,而随环境改变而改变的、不可以共享的状态就是外部状态。内部状态存储于ConcreteFlyweight对象之中,而外部对象则应该考虑由客户端对象存储或计算。当调用Flyweight对象的操作时,将该状态传递给它。
在实际使用中,能够共享的内部状态是有限的,因此享元对象一般都设计为较小的对象,它所包含的内部状态较少,这种对象也成为细粒度对象。
③、解决什么问题(出现的背景)?
面向对象技术可以很好的解决一写灵活性或扩展性问题,但在很多情况下需要在系统中增加类和对象的个数。当对象数量太多时,将导致运行代价过高,带来性能下降,内存溢出等问题。为了解决这一问题便诞生了享元模式。把其中具有相同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
④、如何解决?
用唯一标识码(key)判断,如果内存中有,则返回这个唯一标识码所标识的对象。
⑤、何时使用?
系统有大量相似的对象;需要缓冲池的场景。
⑥、享元模式的核心是什么?
享元模式的核心在于享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,用户需要对象时,首先从享元池中获取,如果享元池不存在,则创建一个新的享元对象返回给用户,并在享元池中保存新增对象。
⑦、享元模式优缺点?
优点:大大较少对象的创建,降低系统的内存,使效率提高。
缺点:提高了系统的复杂度,需要分类出外部状态和内容状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。
二、图
①、结构图
②、拓展图
公用一个Hello World!对象,其中字符串“Hello World!”为内部状态,可共享;字体颜色为外部状态,不可共享,由客户端设定。即内部状态存储与享元对象内部,而外部状态则有客户端来考虑设定。
三、代码
①、代码类图
②、代码
客户端类
//客户端类
static void Main(string[] args)
{
WebSiteFactory f = new WebSiteFactory(); //创建一个享元池:实例化一个网络工厂类,对象f以哈希表的方式存储
WebSite fx = f.GetWebSiteCateGory("产品展示"); //建立一个网站fx对象:调取f对象的GetWebiteCateGory方法,获取网站类型,并将其赋值给fx
fx.use(new User("路飞")); //调用网站的use方法,并将外部状态用户添加至显示信息里
WebSite fy = f.GetWebSiteCateGory("产品展示"); //创建一个类型为产品展示的网站,因享元池内已有实例,所以不用再次创建,直接共享即可
fy.use(new User("索隆"));
WebSite fz = f.GetWebSiteCateGory("产品展示"); //共享享元池内的“产品展示”
fz.use(new User("山治"));
WebSite fl = f.GetWebSiteCateGory("博客"); //在享元池内实例化一个博客类型的网站。
fl.use(new User("布鲁克"));
WebSite fm = f.GetWebSiteCateGory("博客");
fm.use(new User("弗兰奇"));
WebSite fn = f.GetWebSiteCateGory("博客");
fn.use(new User("乔巴"));
Console.WriteLine("网站分类总数为{0}",f.GetWebSiteCount()); //获取不同类型的网站数量
Console.Read();
}
用户类
//用户类
public class User
{
private string name;
public User (string name) //创建User构造函数,获取用户名
{
this.name = name;
}
public string Name
{
get { return name; }
}
}
网站抽象类
//网站抽象类
abstract class WebSite //创建一个抽象的网站类
{
public abstract void use(User user); //创建一个抽象的网站使用方法,参数为用户
}
具体网站类
//具体网站类
class ConcreteWebSite:WebSite //创建一个具体的网站类
{
private string name = ""; //声明一个name变量,并赋予初始值
public ConcreteWebSite(string name) //为此类创建构造函数,参数为网站名称
{
this.name = name;
}
public override void use(User user) //传递的不再是之前的已有的整数类,而是我们自定义的User类,user是对象,而非向整数类中一个具体的数字,需要调取属性使用
{
Console.WriteLine("网站分类:"+name+" 用户:{0}",user.Name);
}
}
网站工厂类
//网站工厂类
class WebSiteFactory
{
private Hashtable flyweights = new Hashtable(); //创建一个享元池(空的):私有的哈希表类,名称为flyweights
public WebSite GetWebSiteCateGory(string key) //创建一个WebSite类型返回值GetWebSiteCateGory()方法获取网站类型
{ //判断享元池中是否包含此类型
if (!flyweights.ContainsKey(key)) //如果不包含
flyweights.Add(key, new ConcreteWebSite(key)); //则创建对象,并将其添加至享元池
return ((WebSite)flyweights[key]); //如果包含则直接返回对象
}
public int GetWebSiteCount() //创建一个返回值为int类型的GetWebSiteCount()方法
{
return flyweights.Count; //返回哈希表中的数量
}
}
四、拓展
https://blog.****.net/justloveyou_/article/details/55045638
https://blog.****.net/z_s_z2016/article/details/80977073