一个人给一家企业做网站,然后他的好多朋友也希望做这样的网站,但要求不太一样,有的人希望是新闻发布形式的,有人希望是博客形式,而且都希望在费用上大大降低,可是每个网站租用一个空间,费用上降低也是不太可能的,怎么办呢?
如果100家企业来做网站,就必须申请100个空间,用100个数据库有,用类似的代码复制100遍,如果有bug或新的需求改动,维护量就太可怕了。
如果大家的网站共用一套代码,就好了。大型的博客网站,里面的每一个博客或商家也可以理解为一个小的网站,但它们是如何做的?
利用用户ID号的不同,来区分不同的用户,具体数据和模板可以不同,但代码核心和数据库却是共享了。
享元模式,运用共享技术有效的支持大量细粒度的对象。
根据享元模式写一个帮人做网站的代码。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace Flyweight
{
//网站抽象类
abstract class WebSite
{
public abstract void Use();
}
//具体网站类
class ConcreteWebSite : WebSite
{
private string name = "";
public ConcreteWebSite(string name)
{
this.name = name;
}
public override void Use()
{
Console.WriteLine("网站分类" + name);
}
}
//网站工厂类
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];
}
//得到实例的个数
public int GetWebSiteCount()
{
return flyweights.Count;
}
}
class Program
{
static void Main(string[] args)
{
WebSiteFactory f = new WebSiteFactory();
//实例化产品展示的网站对象
WebSite fx = f.GetWebSiteCategory("产品展示");
fx.Use();
//共享上方生成的对象,不再实例化
WebSite fy = f.GetWebSiteCategory("产品展示");
fy.Use();
WebSite fz = f.GetWebSiteCategory("产品展示");
fz.Use();
WebSite fl = f.GetWebSiteCategory("博客");
fl.Use();
WebSite fm = f.GetWebSiteCategory("博客");
fm.Use();
WebSite fn = f.GetWebSiteCategory("博客");
fn.Use();
//统计实例化个数,结果应该为2
Console.WriteLine("网站分类总数为{0}", f.GetWebSiteCount());
Console.Read();
}
}
}
这样是有问题的,给企业建的网站不是一家企业的,它们的数据不会相同,所以至少它们都应该有不同的账号,怎么办呢?
实际上没有体现对象间的不同,只体现了它们共享的部分。
享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据,如果能发现这些实例除了几个参数外基本都是相同的,有时就能够受大幅度地减少需要实例化的类的数量,如果能把那些参数移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目。
客户的账号就是外部状态,应该由专门的对象来处理。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace Flyweight
{
//网站抽象类
abstract class WebSite
{
//使用方法需要传递用户对象
public abstract void Use(User user);
}
//具体网站类
class ConcreteWebSite : WebSite
{
private string name = "";
public ConcreteWebSite(string name)
{
this.name = name;
}
//实现Use方法
public override void Use(User user)
{
Console.WriteLine("网站分类" + name + " 用户:" + user.Name);
}
}
//网站工厂类
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];
}
//得到实例的个数
public int GetWebSiteCount()
{
return flyweights.Count;
}
}
//用户
class User
{
private string name = "";
public User(string name)
{
this.name = name;
}
public string Name
{
get { return name; }
}
}
class Program
{
static void Main(string[] args)
{
WebSiteFactory f = new WebSiteFactory();
//实例化产品展示的网站对象
WebSite fx = f.GetWebSiteCategory("产品展示");
fx.Use(new User("小爱"));
//共享上方生成的对象,不再实例化
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("南海鳄神"));
//统计实例化个数,结果应该为2
Console.WriteLine("网站分类总数为{0}", f.GetWebSiteCount());
Console.Read();
}
}
}
何时使用享元模式呢?如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销就应该考虑使用还有就是对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。