享元模式(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 ()); }