设计模式深入学习--Flyweight 享元模式(结构型模式)

   这次和大家一起学习一下 享元设计模式。我们在开发游戏的时候经常可能会遇到使用大量细粒度对象,比如三消游戏的 这些一个个小方块。又或者一个大型模拟游戏里面的Ai人物,或者围棋里面的黑白子,等等。。。 我们一般的优化方法就是使用对象池,将使用的拿出来,不使用了又放回去,这样的方法虽然好,但还是没有根本解决对象被大量new出来的事实,导致内存变得非常大,而Flyweight 享元模式就是通过共享技术来有效地支持大量细粒度的对象,从而解决这样的问题我们先来看一个Flyweight 享元模式的示例代码:

/// <summary>
 /// flyweight类 拥有享元类的超类或接口,通过这个接口,flyweight可以接受并作用于外部状态
 /// </summary>
 abstract class flyweight
 {
     public abstract void Operation(int extrinsicstate);
 }
 
 
 
 /// <summary>
 /// ConcreteFlyweight是继承flyweight超类货实现flyweight接口,并为内部状态增加存储空间
 /// </summary>
 class ConcreteFlyweight : flyweight
 {
     public override void Operation(int extrinsicstate)
     {
         Console.WriteLine("具体flyweight:" + extrinsicstate);
     }
 }
 
 /// <summary>
 /// UnsharedConcreteFlyweight是指那些不需要共享的flyweight子类 因为flyweight接口共享成为可能,但它并不强制共享
 /// </summary>
 class UnsharedConcreteFlyweight : flyweight
 {
     public override void Operation(int extrinsicstate)
     {
         Console.WriteLine("不共享的具体flyweight:" + extrinsicstate);
     }
 }
 
 
 /// <summary>
 /// flyweightFactory,是一个享元工厂,用来创建并管理flyweight对象,它主要用来确保合理地共享flyweight,
 /// 当用户请求一个flyweight时,flyweightFactory对象提供一个已创建的实例或者创建一个
 /// </summary>
 class flyweightFactory
 {
     private Hashtable flyweights = new Hashtable();
 
     public flyweightFactory()
     {
         flyweights.Add("X", new ConcreteFlyweight());
         flyweights.Add("Y", new ConcreteFlyweight());
         flyweights.Add("Z", new ConcreteFlyweight());
     }
 
     public flyweight GetFlyweight(string key)
     {
         return ((flyweight)flyweights[key]);
     }
 
 }
          从示例可以看出,我们先构造一个虚类flyweight ,然后和一个具体实现的子类ConcreteFlyweight,这个子类就是共享的数据类,比如要做一把枪,枪的类型不一样,外观不一样,但都有一个共同点,就是有一个能开枪的方法,或者存储其他共有的数据。而就可以用 ConcreteFlyweight类来存放。 接下来再构造一个子类 UnsharedConcreteFlyweight,而刚才说的外观,类型不一样 就把这些不共享的数据存放到该类下。 最后就是来构造一个工厂类flyweightFactory。 工厂类初始化一个Hashtable 字典,用来存放共有类数据。还有一个返回类型的value的方法。 ok,模板有了,我们就在初始化的时候声明一下参数,运行起来看看效果:
int extrinsicstate = 22;
 
        flyweightFactory ff = new flyweightFactory();
 
        flyweight fx = ff.GetFlyweight("X");
        fx.Operation(--extrinsicstate);
 
        flyweight fy = ff.GetFlyweight("Y");
        fy.Operation(--extrinsicstate);
 
        flyweight fz = ff.GetFlyweight("Z");
        fz.Operation(--extrinsicstate);
 
        UnsharedConcreteFlyweight uf = new UnsharedConcreteFlyweight();
 
        uf.Operation(--extrinsicstate);
 
        Console.ReadKey();

        

            现在我们运行一下看看,可以看到,已经就打印出来了3个具体的ConcreteFlyweight类,而其实他们都是一个实例。原理我们弄懂了,我们再来自己做个小案例玩玩,展示下享元设计模式的强大用法。

/// <summary>
/// 敌人抽象类
/// </summary>
abstract class Eneny
{
    public abstract void Use(User user);
}
 
 
/// <summary>
/// 具体敌人类
/// </summary>
class ConcreteEneny : Eneny
{
    private string name = "";
    public override void Use(User user)
    {
        Console.WriteLine("敌人分类:" + name+ '\n'+"名字:"+user.Name);
    }
 
    public ConcreteEneny(string name)
    {
        this.name = name;
    }
}
 
/// <summary>
/// 敌人工厂类
/// </summary>
class EnenyFactory
{
    private Hashtable flyweights=new Hashtable();
 
    //获得敌人分类
    public Eneny GetEnenyCategory(string key)
    {
        if (!flyweights.ContainsKey(key))
        {
            flyweights.Add(key,new ConcreteEneny(key));
 
        }
        return ((Eneny) flyweights[key]);
    }
 
    public int GetEnenyCount()
    {
        return flyweights.Count;
    }
}
 
/// <summary>
/// 用户类
/// </summary>
public class User
{
    private string name;
 
    public User(string name)
    {
        this.name = name;
    }
 
    public string Name
    {
        get { return name; }
    }
}
        我们模仿制作一个敌人类 Eneny,准确来说应该是一个多种类型兵种的管理器, 首先是一个敌人抽象类,里面调用到一个User类,user类存放该人物名字,这个就代表我们在示例里面的不共享类。 然后是一个具体的敌人类ConcreteEneny,重写了父类User方法。敌人工厂类EnenyFactory ,存放敌人类的Hashtable字典,还有两个方法,一个获得敌人的分类。  一个返回分类的实例化总数。最后,实例化看看效果.

EnenyFactory wsf = new EnenyFactory();
 
           //实例化
           Eneny fx = wsf.GetEnenyCategory("人族");
           fx.Use(new User("矮人火枪手"));
           //共享上面生成的对象,不再实例化
           Eneny fy = wsf.GetEnenyCategory("人族");
           fy.Use(new User("步兵"));
           //共享上面生成的对象,不再实例化
           Eneny fz = wsf.GetEnenyCategory("人族");
           fz.Use(new User("农民"));
           //实例化
           Eneny fl = wsf.GetEnenyCategory("兽族");
           fl.Use(new User("苦工"));
           //共享上面生成的对象,不再实例化
           Eneny fm = wsf.GetEnenyCategory("兽族");
           fm.Use(new User("巨魔猎头者"));
           //共享上面生成的对象,不再实例化
           Eneny fn = wsf.GetEnenyCategory("兽族");
           fn.Use(new User("牛头人"));
 
           Console.WriteLine("敌人分类总数:" + wsf.GetEnenyCount());
 
           Console.ReadKey();
        代码可以看到,我们声明了人族和兽族两个分类,然后分别传入了 矮人火枪手,步兵,农民 和苦工,巨魔猎头者,牛头人 ,表面上看起来我们构造了6个不同的敌人,但是输出我们可以看到分类总数其实只有2个,他们共享了一套相同的模板,只是名字不同样,是由我们外部传入的。

 


   现在可以看出Flyweight 享元模式的好处了吧,当我们需要大量复用一个细粒度高的对象时候,我们可以采用享元设计模式,可以给我们的CPU,内存减少了极大的开销,只要能共享的数据就都采用一个模板复用,不能共享的数据就采用外部传入的方式来实现。我们再来复习下Flyweight 享元模式的几个要点:
   Flyweight 享元模式主要解决面向对象的代价问题,一般不触及面向对象的抽象性问题。  
   Flyweight 享元模式采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力,在具体实现方面,要注意对象状态的处理。
   对象的数量太大从而导致对象内存开销加大,什么样的数量才算大?这需要我们仔细地根据具体应用情况进行评估,而不能意淫的拍脑袋决定。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值