Flyweight
享元设计模式是一种结构型设计模式,它主要解决的问题是:由于(同类)对象的数量太大,采用面向对象时给系统带来了难以承受的内存开销。比如有这样一个场景:一个停车场中有
1000
辆汽车,我们所定义的汽车对象占用内存
0.3M
,那么要实例化
1000
辆就是
300M
。由此可见,在这种情况下采用一般的面向对象方式出现了大量细粒度的对象会很快充斥在系统中,从而带来很高的运行是代价(这里指的代价是内存开销的代价)。
GoF
《设计模式》中说道:运用共享技术有效的支持大量细粒度的对象。
Flyweight
模式的结构大概是这样的:
(这张图是按照我的理解画出来的,如果有不对的地方还请帮我指正,谢谢),从图上可以看出
Flyweight
模式是将相同的对象存为一个,就是在
FlyweightFactory
中对于实例化对象的判断。这样,客户代码即使是调用
1000000
个对象,如果这些对象的种类只有一个的话,对于内存的分配上也只是分配了一个对象的空间。但是有一点我想要注意:就是对于引用对象来说,这样做,如果其中某一个对象发生变化,那么同类中的所有对象也会随之变化。
来看看程序,定义一个场景:有一个汽车类型,客户程序要实例化
1000
个,实例化后查看一下内存分配情况。
普通的面向对象方式:
class
Class1
{
[STAThread]
static
void
Main(string[] args)
{
Console.WriteLine("
实例化前:"
+ GC.GetTotalMemory(false));
ArrayList list = new ArrayList(1000);
for(int i = 0;i < 1000;i++)
{
Car car = new Car("4.2M","Wheel","NeedForSpeed","BMW","Black");
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
Main(string[] args)
{
Console.WriteLine("
实例化前:"
+ GC.GetTotalMemory(false));
ArrayList list = new ArrayList(1000);
for(int i = 0;i < 1000;i++)
{
FlyWeightCar car = FlyWeightFactory.CreateInit("4.2M","Wheel","NeedForSpeed","BMW","Black");
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
、对象的数量太大从而导致对象内存开销加大(这个数量要经过评估,而不能凭空臆断)