您的位置:首页 > 移动开发 > Unity3D

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

2017-01-16 10:22 603 查看
   这次和大家一起学习一下 享元设计模式。我们在开发游戏的时候经常可能会遇到使用大量细粒度对象,比如三消游戏的 这些一个个小方块。又或者一个大型模拟游戏里面的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 享元模式采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力,在具体实现方面,要注意对象状态的处理。
   对象的数量太大从而导致对象内存开销加大,什么样的数量才算大?这需要我们仔细地根据具体应用情况进行评估,而不能意淫的拍脑袋决定。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Unity 设计模式