设计模式学习笔记(十二)——Flyweight享元模式
GoF《设计模式》中说道:运用共享技术有效的支持大量细粒度的对象。
Flyweight模式的结构大概是这样的:
(这张图是按照我的理解画出来的,如果有不对的地方还请帮我指正,谢谢),从图上可以看出Flyweight模式是将相同的对象存为一个,就是在FlyweightFactory中对于实例化对象的判断。这样,客户代码即使是调用1000000个对象,如果这些对象的种类只有一个的话,对于内存的分配上也只是分配了一个对象的空间。但是有一点我想要注意:就是对于引用对象来说,这样做,如果其中某一个对象发生变化,那么同类中的所有对象也会随之变化。
来看看程序,定义一个场景:有一个汽车类型,客户程序要实例化1000个,实例化后查看一下内存分配情况。
普通的面向对象方式:
class Class1
{
[STAThread]
static void
{
Console.WriteLine("实例化前:" + GC.GetTotalMemory(false));
ArrayList list = new ArrayList(1000);
for(int i = 0;i < 1000;i++)
{
Car car = new Car("
list.Add(car);
}
Console.WriteLine("实例化后:" + GC.GetTotalMemory(false));
Console.Read();
}
}
public class Car
{
private string body;
private string wheel;
private string engine;
private string brand;
private string color;
public string Body
{
get{return body;}
set{body = value;}
}
public string Wheel
{
get{return wheel;}
set{wheel = value;}
}
public string Engine
{
get{return engine;}
set{engine = value;}
}
public string Brand
{
get{return brand;}
set{brand = value;}
}
public string Color
{
get{return color;}
set{color = value;}
}
public Car(string body,string wheel,string engine,string brand,string color)
{
Body = body;
Wheel = wheel;
Engine = engine;
Brand = brand;
Color = color;
}
}
内存分配情况如下:
实例化前:16384
实例化后:65536
然后再用Flyweight模式方式程序做一下比较:
class Class1
{
[STAThread]
static void
{
Console.WriteLine("实例化前:" + GC.GetTotalMemory(false));
ArrayList list = new ArrayList(1000);
for(int i = 0;i < 1000;i++)
{
FlyWeightCar car = FlyWeightFactory.CreateInit("
list.Add(car);
}
Console.WriteLine("实例化后:" + GC.GetTotalMemory(false));
Console.Read();
}
}
public class FlyWeightFactory
{
private static FlyWeightCar car;
private static Hashtable table = new Hashtable();
public static FlyWeightCar CreateInit(string body,string wheel,string engine,string brand,string color)
{
if(table[brand] != null)
{
car = (FlyWeightCar)table[brand];
}
else
{
car = new FlyWeightCar();
car.Brand = brand;
car.CarBody = new CarBody(body,wheel,engine,color);
table.Add(brand,car);
}
return car;
}
}
public class FlyWeightCar
{
private string brand;
public string Brand
{
get
{
return brand;
}
set
{
brand = value;
}
}
private CarBody carbody;
public CarBody CarBody
{
get
{
return carbody;
}
set
{
this.carbody = value;
}
}
}
public class CarBody
{
private string body;
private string wheel;
private string engine;
private string color;
public string Body
{
get{return body;}
set{body = value;}
}
public string Wheel
{
get{return wheel;}
set{wheel = value;}
}
public string Engine
{
get{return engine;}
set{engine = value;}
}
public string Color
{
get{return color;}
set{color = value;}
}
public CarBody(string body,string wheel,string engine,string color)
{
Body = body;
Wheel = wheel;
Engine = engine;
Color = color;
}
}
内存分配情况:
实例化前:16384
实例化后:40960
从数字上不难看出内存分配的容量节省了不少,而且随着数量的增加,差距会更大,当然我也测试了一下数量减少的情况,当我实例化100个对象是结果是普通方式的内存分配更小一些,所以,在使用时,我们一定要对所实例化对象的个数进行评估,否则的话会适得其反。
Flyweight模式的几个要点:
1、面向对象很好的解决了抽象性的问题,但是作为一个运行在机器中的程序实体,我们需要考虑对象的代价问题。Flyweight设计模式主要解决面向对象的代价问题,一般不触及面向对象的抽象性问题。
2、Flyweight采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实现方面,要注意对象的状态处理。
3、对象的数量太大从而导致对象内存开销加大(这个数量要经过评估,而不能凭空臆断)