设计模式学习笔记之 Composite 

     Composite模式的目的是让用户在处理同一系列的简单和复杂对象时(复杂对象可能包含简单对象),可以采用一致的方式,而不是区别简单和复杂对象再进行不同的操作,即解除了复杂的对象的内部结构与用户代码之间的耦合关系。

     在遥远的艾泽拉斯大陆(wow病又发作了),有一个神秘的地方称为奥达曼,那里有一种名为Obsidian Sentinel  (黑耀石哨兵)的怪,它在被攻击的时候会不时的从身上掉下小型的Obsidian Sentinel,但是这种小的就不能再分了。我们可以想到,它们应当都属于Obsidian Sentinel,但是一种是复杂的Obsidian Sentinel,可以再分,一种是简单的Obsidian Sentinel,不能再分。比较丑陋的实现是这样的:

public abstract class ObsidianSentinel
{
         
public abstract void SetObsidianSentinel();
}


public class AtomObsidianSentinel : ObsidianSentinel
{
         
public override void SetObsidianSentinel()
         
{
                
//do sth to descript ObsidianSentinel
         }

}


public class ComplexObsidianSentinel : StoneSentinel
{
         
public override void SetObsidianSentinel()
         
{
                
//do sth to descript ObsidianSentinel
         }

         
public override void ChangeToSmall()
         
{
                Console.WriteLine(
"Change To Small");
         }

}


     在客户调用的时候则需要判断是AtomObsidianSentinel还是ComplexObsidianSentinel,因为它们的内部调用完全不同,对于ComplexObsidianSentinel来说,有一个AtomObsidianSentinel没有的方法,而且SetObsidianSentinel方法也应该是以一种递归的方法来对其中的每个AtomObsidianSentinel进行描述的,也就是说ComplexObsidianSentinel即是对象,也是AtomObsidianSentinel的容器。

     下面我们应用Composite模式来修改代码:

       public abstract class ObsidianSentinel
       
{
            
public abstract void SetObsidianSentinel();
            
public abstract void ChangeToSmall();
       }

       
public class ComplexObsidianSentinel : ObsidianSentinel
       
{
            
public override void SetObsidianSentinel()
            
{
                
//do sth to descript ObsidianSentinel
                
//foreach(ObsidianSentinel in ComplexObsidianSentinel)
                
//{
                
//    if (ObsidianSentinel is AtomObsidianSentinel)
                
//    {
                
//        //do sth to descript ObsidianSentinel
                
//    }
                
//    if (ObsidianSentinel is ComplexObsidianSentinel)
                
//    {
                
//        ObsidianSentinel.SetObsidianSentinel()
                
//    }
                
//}
            }

            
public override void ChangeToSmall()
            
{
                Console.WriteLine(
"Change To Small");
            }

       }

       
public class AtomObsidianSentinel : ObsidianSentinel
       
{
            
public override void SetObsidianSentinel()
            
{
                
//do sth to descript ObsidianSentinel
            }

            
public override void ChangeToSmall()
            
{
                
throw new Exception("Cann't to small");
            }

       }


     我们统一了它们的接口,当不适当的调用ChangeToSmall方法时抛出异常。同时我们把递归描述放到复杂类内部。对用户来说,它们在调用SetObsidianSentinel时不需要了解是哪种对象。这样做的优点在于透明性比较高,因为有统一的接口。缺点在于安全性比较低,因为不适当的调用方法在编译阶段不会出现错误,在运行阶段才会报错。

     我们还有另一种应用Composite模式的方法:

        public abstract class ObsidianSentinel
          
{
            
public abstract void SetObsidianSentinel();
          }

        
public class ComplexObsidianSentinel : ObsidianSentinel
          
{
              
public override void SetObsidianSentinel()
              
{
                
//do sth to descript ObsidianSentinel
                
//foreach(ObsidianSentinel in ComplexObsidianSentinel)
                
//{
                
//    if (ObsidianSentinel is AtomObsidianSentinel)
                
//    {
                
//        //do sth to descript ObsidianSentinel
                
//    }
                
//    if (ObsidianSentinel is ComplexObsidianSentinel)
                
//    {
                
//        ObsidianSentinel.SetObsidianSentinel()
                
//    }
                
//}
              }

              
public void ChangeToSmall()
              
{
                Console.WriteLine(
"Change To Small");
              }

        }

        
public class AtomObsidianSentinel : ObsidianSentinel
        
{
            
public override void SetObsidianSentinel()
            
{
                
//do sth to descript ObsidianSentinel
            }

        }


     接口中已不包含复杂对象独有的方法。这样的做法使得安全性提高了,但是却降低了透明性。客户在使用ChangeToSmall方法前必须了解对象是否为复杂对象,否则不能通过编译。

     上面两种方法各有利弊,透明和安全是很难两全齐美的。

参考:MSDNWebCast  C#设计模式纵横谈      李建忠

     回到目录
  

posted on 2006-09-10 17:21  aiya  阅读(367)  评论(0)    收藏  举报