目录
意图(Intention)
运用共享技术有效地支持大量细粒度的对象。
结构(Structure)
其中,
Flyweight抽象享元对象:为具体享元角色规定了必须实现的方法,而外部状态是以参数的形式传入此方法。
ConcreteFlyweight具体享元角色:实现抽象享元角色规定的方法。如果存在内蕴状态,就负责为内蕴状态提供存储空间。
UnsharedConcreteFlyweight非共享具体享元角色:并非所有的Flyweight子类都需要被共享。Flyweight接口使共享变成可能,但是它并不强制共享。
FlyweightFactory享元工厂角色:负责创建和管理享元角色,提供一个已经创建的实例或者不存在时创建一个实例。
Clint客户端角色:维护对所有享元对象的引用,而且还需要存储对应的外蕴状态。
两个状态
内蕴状态/内部状态:存储在享元内部,不随环境改变而有所不不同,可共享。
外蕴状态/外部状态:不可共享,随环境改变而改变,由客户端来维持。
Flyweight模式的几个要点
1.面向对象很好地解决了抽象性的问题,但是作为一个运行在机器中的程序实体,我们需要考虑对象的代价问题。Flayweight设计模式主要解决面向对象的代价问题,一般不触及面向对象的抽象性问题。
2.Flyweight采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实现方面,要注意对象状态的处理。
3.对象的数量太大从而导致对象内存开销加大--什么样的数量才算大?这需要我们仔细的根据具体应用情况进行评估,而不能凭空臆断。
适用场景
1.一个应用程序使用了大量的对象。
2.完全由于使用大量的对象,造成很大的存储开销。
3.对象的大多数状态都可以变为外部状态。
4.如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
一句话来说,就是如果一个应用程序使用了大量的对象,而这些对象造成了很大的存储开销的时候就可以考虑是否可以使用享元模式。
Example
背景:需要做3个产品展示网站,3个博客网站,这就需要6个网站类的实例,如果每一个都需要一个实例的话,随着网站的增多,实例数量也就增多,对服务器资源浪费就很严重。这就需要用到享元模式来解决这个问题了。其实,3个产品展示网站只需要实例化1个就可以,3个博客网站也只需要实例化出1个,然后根据不同的用户ID来进行区分(外蕴状态),核心代码和数据库共享。
代码实现
网站抽象类:对应于结构图中Flyweight抽象享元对象
abstract class Website
{
//“使用”方法需要传递“用户”对象
public abstract void Use(User user);
}
具体网站类:对应于结构图中的ConcreteFlyweight具体享元角色
class ConcreteWebsite : Website
{
private string name = "";
public ConcreteWebsite(string name)
{
this.name = name;
}
//实现User方法
public override void Use(User user)
{
Console.WriteLine("网站分类:"+name+" 用户:"+user.Name);
}
}
网站工厂类:对应于结构图中的 FlyweightFactory享元工厂角色,在创建不同种类的网站时,先判断该网站实例是否存在,如果存在,直接返回,若不存在,先实例化一个再返回
class WebsiteFactory
{
private Hashtable flyweights = new Hashtable();
public Website GetWebsiteCategory(string key)
{
if (!flyweights.ContainsKey(key))
{
flyweights.Add(key, new ConcreteWebsite(key));
}
return ((Website)flyweights[key]);
}
}
客户端代码:创建了小王的产品展示网站,小李的产品展示网站,小王的博客网站,小李的博客网站,但是实际上产品展示网站和博客网站只实例化了一次,其中外部状态用户ID是通过User user这个参数传入的。
WebsiteFactory f = new WebsiteFactory();
//实例化“产品展示网站”对象
Website fx = f.GetWebsiteCategory("产品展示");
fx.Use(new User("小王"));
//共享上方生成的“产品展示网站”对象,不再实例化
Website fy = f.GetWebsiteCategory("产品展示");
fy.Use(new User("小李"));
//实例化“博客”的“网站”对象
Website fl = f.GetWebsiteCategory("博客");
fl.Use(new User("小王"));
//共享上方生成的“博客网站”对象,不再实例化
Website fm = f.GetWebsiteCategory("博客");
fm.Use(new User("小李"));
运行结果如下
如有问题,欢迎指正~~~~