íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
主要内容:íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
1.íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
Flyweight模式解说íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
2..NET中的Flyweight模式íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
3.Flyweight模式的实现要点íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
……íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
概述íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
面向对象的思想很好地解决了抽象性的问题,一般也不会出现性能上的问题。但是在某些情况下,对象的数量可能会太多,从而导致了运行时的代价。那么我们如何去避免大量细粒度的对象,同时又不影响客户程序使用面向对象的方式进行操作?íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
意图íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
运用共享技术有效地支持大量细粒度的对象。[GOF 《设计模式》]íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
结构图íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

1íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
Flyweight
模式结构图

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
生活中的例子íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
享元模式使用共享技术有效地支持大量细粒度的对象。公共交换电话网(PSTN)是享元的一个例子。有一些资源例如拨号音发生器、振铃发生器和拨号接收器是必须由所有用户共享的。当一个用户拿起听筒打电话时,他不需要知道使用了多少资源。对于用户而言所有的事情就是有拨号音,拨打号码,拨通电话。íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

使用拨号音发生器例子的享元模式对象图

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
Flyweight模式解说íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
Flyweight在拳击比赛中指最轻量级,即“蝇量级”,这里翻译为“享元”,可以理解为共享元对象(细粒度对象)的意思。提到Flyweight模式都会一般都会用编辑器例子来说明,这里也不例外,但我会尝试着通过重构来看待Flyweight模式。考虑这样一个字处理软件,它需要处理的对象可能有单个的字符,由字符组成的段落以及整篇文档,根据面向对象的设计思想和Composite模式,不管是字符还是段落,文档都应该作为单个的对象去看待,这里只考虑单个的字符,不考虑段落及文档等对象,于是可以很容易的得到下面的结构图:íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

图3

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
示意性实现代码:íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
// "Charactor"íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
public abstract class CharactoríÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
//FieldsíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    protected char _symbol;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
protected int _width;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
protected int _height;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
protected int _ascent;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
protected int _descent;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
protected int _pointSize;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
//MethodíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public abstract void Display();íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
}
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
// "CharactorA"íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
public class CharactorA : CharactoríÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
{ íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
// Constructor íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public CharactorA()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
     
this._symbol = 'A';íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
     
this._height = 100;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
     
this._width = 120;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
     
this._ascent = 70;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
     
this._descent = 0;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
     
this._pointSize = 12;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
//MethodíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public override void Display()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        Console.WriteLine(
this._symbol);íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
}
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
// "CharactorB"íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
public class CharactorB : CharactoríÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
// Constructor íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public CharactorB()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._symbol = 'B';íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._height = 100;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._width = 140;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._ascent = 72;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._descent = 0;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._pointSize = 10;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
//MethodíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public override void Display()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        Console.WriteLine(
this._symbol);íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
}
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
// "CharactorC"íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
public class CharactorC : CharactoríÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
// Constructor íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public CharactorC()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._symbol = 'C';íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._height = 100;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._width = 160;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._ascent = 74;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._descent = 0;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._pointSize = 14;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
//MethodíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public override void Display()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        Console.WriteLine(
this._symbol);íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
}
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
好了,现在看到的这段代码可以说是很好地符合了面向对象的思想,但是同时我们也为此付出了沉重的代价,那就是性能上的开销,可以想象,在一篇文档中,字符的数量远不止几百个这么简单,可能上千上万,内存中就同时存在了上千上万个
Charactor对象,这样的内存开销是可想而知的。进一步分析可以发现,虽然我们需要的Charactor实例非常多,这些实例之间只不过是状态不同而已,也就是说这些实例的状态数量是很少的。所以我们并不需要这么多的独立的Charactor实例,而只需要为每一种Charactor状态创建一个实例,让整个字符处理软件共享这些实例就可以了。看这样一幅示意图:íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

4

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
现在我们看到的ABC三个字符是共享的,也就是说如果文档中任何地方需要这三个字符,只需要使用共享的这三个实例就可以了。然而我们发现单纯的这样共享也是有问题的。虽然文档中的用到了很多的A字符,虽然字符的symbol是相同的,它可以共享;但是它们的pointSize却是不相同的,即字符在文档中中的大小是不相同的,这个状态不可以共享。为解决这个问题,首先我们将不可共享的状态从类里面剔除出去,即去掉pointSize个状态(只是暂时的J),类结构图如下所示:íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

5

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
示意性实现代码:íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
// "Charactor"íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
public abstract class CharactoríÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
//FieldsíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    protected char _symbol;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
protected int _width;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
protected int _height;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
protected int _ascent;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
protected int _descent;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
//MethodíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public abstract void Display();íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
}
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
// "CharactorA"íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
public class CharactorA : CharactoríÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
// Constructor íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public CharactorA()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._symbol = 'A';íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._height = 100;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._width = 120;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._ascent = 70;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._descent = 0;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
//MethodíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public override void Display()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        Console.WriteLine(
this._symbol);íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
}
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
// "CharactorB"íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
public class CharactorB : CharactoríÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
// Constructor íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public CharactorB()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._symbol = 'B';íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._height = 100;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._width = 140;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._ascent = 72;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._descent = 0;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
//MethodíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public override void Display()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        Console.WriteLine(
this._symbol);íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
}
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
// "CharactorC"íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
public class CharactorC : CharactoríÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
// Constructor íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public CharactorC()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._symbol = 'C';íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._height = 100;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._width = 160;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._ascent = 74;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._descent = 0;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
//MethodíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public override void Display()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        Console.WriteLine(
this._symbol);íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
}
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
好,现在类里面剩下的状态都可以共享了,下面我们要做的工作就是控制
Charactor类的创建过程,即如果已经存在了“A”字符这样的实例,就不需要再创建,直接返回实例;如果没有,则创建一个新的实例。如果把这项工作交给Charactor类,即Charactor类在负责它自身职责的同时也要负责管理Charactor实例的管理工作,这在一定程度上有可能违背类的单一职责原则,因此,需要一个单独的类来做这项工作,引入CharactorFactory类,结构图如下:íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

6

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
示意性实现代码:íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
// "CharactorFactory"íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
public class CharactorFactoryíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
// FieldsíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    private Hashtable charactors = new Hashtable();íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
// Constructor íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public CharactorFactory()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        charactors.Add(
"A", new CharactorA());íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        charactors.Add(
"B", new CharactorB());íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        charactors.Add(
"C", new CharactorC());íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
      íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
// MethodíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public Charactor GetCharactor(string key)íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        Charactor charactor
= charactors[key] as Charactor;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
if (charactor == null)íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
           
switch (key)íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
           
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
               
case "A": charactor = new CharactorA(); break;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
               
case "B": charactor = new CharactorB(); break; íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
               
case "C": charactor = new CharactorC(); break;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
               
//íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
            }íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
            charactors.Add(key, charactor);íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
return charactor;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
}
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
到这里已经完全解决了可以共享的状态(这里很丑陋的一个地方是出现了
switch语句,但这可以通过别的办法消除,为了简单期间我们先保持这种写法)。下面的工作就是处理刚才被我们剔除出去的那些不可共享的状态,因为虽然将那些状态移除了,但是Charactor对象仍然需要这些状态,被我们剥离后这些对象根本就无法工作,所以需要将这些状态外部化。首先会想到一种比较简单的解决方案就是对于不能共享的那些状态,不需要去在Charactor类中设置,而直接在客户程序代码中进行设置,类结构图如下:

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

7

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
示意性实现代码:íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
public class ProgramíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
public static void Main()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        Charactor ca
= new CharactorA();íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        Charactor cb
= new CharactorB();íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        Charactor cc
= new CharactorC();íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
//显示字符íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
//设置字符的大小ChangeSize();íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
public void ChangeSize()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
//在这里设置字符的大小íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
}
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
按照这样的实现思路,可以发现如果有多个客户端程序使用的话,会出现大量的重复性的逻辑,用重构的术语来说是出现了代码的坏味道,不利于代码的复用和维护;另外把这些状态和行为移到客户程序里面破坏了封装性的原则。再次转变我们的实现思路,可以确定的是这些状态仍然属于
Charactor对象,所以它还是应该出现在Charactor类中,对于不同的状态可以采取在客户程序中通过参数化的方式传入。类结构图如下:íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ

8

íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
示意性实现代码:íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
// "Charactor"íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
public abstract class CharactoríÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
//FieldsíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    protected char _symbol;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
protected int _width;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
protected int _height;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
protected int _ascent;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
protected int _descent;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
protected int _pointSize;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
//MethodíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public abstract void SetPointSize(int size);íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
public abstract void Display();íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
}
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
// "CharactorA"íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
public class CharactorA : CharactoríÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
// Constructor íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public CharactorA()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._symbol = 'A';íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._height = 100;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._width = 120;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._ascent = 70;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._descent = 0;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
//MethodíÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    public override void SetPointSize(int size)íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
       
this._pointSize = size;íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
    }
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
public override void Display()íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
   
{íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
        Console.WriteLine(
this._symbol +íÉ ò±?Cçwww.netcsharp.cnMá!¿WeëßfÈ
         
"pointsize:" + this