享元模式(Flyweight)定义:运用共享技术有效地支持大量细粒度的对象。
享元模式的定义提出了两个要求,细粒度和共享对象。因为要求细粒度,所以不可避免地会使对象数量多且性质相近,此时我们就将这些对象的信息分为两个部分:内部状态和外部状态。
享元对象的状态分类:
- 内部状态:在享元对象内部且不会随着环境改变而改变的共享部分
- 外部状态:随环境改变而改变的,不可共享的部分
- (例如五子棋中,棋子的黑白两色是内部状态,棋子的方位坐标是外部状态)
使用场景:
- 程序使用了大量的对象,而这些对象造成了很大的存储开销。
- 对象的大多数状态为外部状态,如果删除了对象的外部状态,那么可以用相对较少的共享对象取代大量对象组。
优点:
- 它通过共享已经存在的对象(相同对象只要保存一份),来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。
缺点:
- 需要维护一个记录了系统已有的所有的享元列表,这本身需要消耗资源。
- 在没有足够多的对象实例可共享时,不要强制使用享元模式,因为为了使对象可以共享,需要将一些状态外部化,这样使得程序的逻辑复杂化。
代码背景: 不同的网站之间差异其实不大,框架都是可共享的,仅仅是网站的功能不同,有的用来展示产品,有的用来发布新闻。
用户类:用于网站的客户账号,是网站类的外部状态
class User
{
private string name;
public User(string name)
{
this.name = name;
}
public string Name
{
get {
return name; }
}
}
网站抽象类:
abstract class WebSite
{
//使用方法需要传递用户对象
public abstract void Use(User user);
}
具体网站类:
class ConcreteWebSite:WebSite
{
private string name = "";
public ConcreteWebSite(string name)
{
this.name = name;
}
public override void Use(User user)//重写Use方法
{
Console.WriteLine("网站分类:" + name +" 用户:"+user.Name) ;
}
}
网站工厂类:
using System.Collections;//为了使用哈希表
class WebSiteFactory
{
private Hashtable flyweights = new Hashtable();
//获得网站分类
public WebSite GetWebSiteCategory(string key)
{
//判断键是不是不存在,这里if语句简写了
if (!flyweights.ContainsKey(key))
flyweights.Add(key,new ConcreteWebSite(key));//是不存在,就以键为name实例化一个ConcreteWebSite对象添加到哈希表
return ((WebSite )flyweights[key]);//返回flyweights键为key的值,并把值强转成WebSite类型
}
//获得网站分类总数
public int GetWebSiteCount()
{
return flyweights.Count;
}
}
客户端:
static void Main(string[] args)
{
WebSiteFactory f = new WebSiteFactory();
WebSite fx = f.GetWebSiteCategory ("产品展示");
fx.Use(new User("咪西"));//实例用户对象,用于Use方法显示
WebSite fy = f.GetWebSiteCategory("产品展示");
fy.Use(new User("啾咪"));
WebSite f1 = f.GetWebSiteCategory("博客");
f1.Use(new User("旧浪"));
WebSite f2 = f.GetWebSiteCategory("小游戏");
f2.Use(new User("7k7k"));
//实际网站只有三种
Console.WriteLine("得到网站分类总数为{0}",f.GetWebSiteCount ());
}