posts - 6, comments - 42, trackbacks - 0, articles - 1

导航

公告

模式探索(1):采用委托实现模版方法

Posted on 2005-12-31 13:09 小象 阅读(...) 评论(...) 编辑 收藏


      由于看的人多,参与讨论的人少,我想可能是我写的过于简略了,所以今天重新编辑了一下。
      模版方法的关键是在父类中的非抽象方法中调用抽象方法,子类各自实现自己父类的抽象方法。子类的区别仅仅是实现方法的不同,其自身原来的优势就是可以在有新的具体类的增加时不用修改抽象类,而客户端的调用则只是通过多态来执行抽象类的方法。在.NET中,我们可以采用委托方法实现相同的目的。
       我们先来看看一般情况下如何实现模版方法:
 

using System;

namespace Basic
{
    
/// <summary>
    
/// Class1 的摘要说明。
    
/// </summary>

    class Class1
    
{
        
/// <summary>
        
/// 应用程序的主入口点。
        
/// </summary>

        [STAThread]
        
static void Main(string[] args)
        
{
            AbstractClass Worker
=new ConcreteClass1();
            Console.WriteLine (Worker.TemplateMethod ());
            Worker
=new ConcreteClass2 ();
            Console.WriteLine(Worker.TemplateMethod ());
            Console.ReadLine ();
        }

    }

}


using System;

namespace Basic
{
    
/// <summary>
    
/// AbstractClass 的摘要说明。
    
/// </summary>

    public abstract class AbstractClass
    
{
        
public AbstractClass()
        
{
            
//
            
// TODO: 在此处添加构造函数逻辑
            
//
        }


        
public string TemplateMethod()
        
{
            
string s="";
            s
+=Title();
            s
+=Body();
            
return s;
        }

        
public abstract string Title();
        
public abstract string Body();
    }

}


using System;

namespace Basic
{
    
/// <summary>
    
/// ConcreteClass 的摘要说明。
    
/// </summary>

    public class ConcreteClass1:AbstractClass
    
{
        
public ConcreteClass1()
        
{
            
//
            
// TODO: 在此处添加构造函数逻辑
            
//
        }

        
public override string Title()
        
{
        
return "标题1";
        }

        
public override string Body()
        
{
        
return "内容1";
        }

    }

}


using System;

namespace Basic
{
    
/// <summary>
    
/// ConcreteClass 的摘要说明。
    
/// </summary>

    public class ConcreteClass2:AbstractClass
    
{
        
public ConcreteClass2()
        
{
            
//
            
// TODO: 在此处添加构造函数逻辑
            
//
        }

        
public override string Title()
        
{
        
return "标题2";
        }

        
public override string Body()
        
{
        
return "内容2";
        }

    }

}

结果显示:
标题1内容1
标题2内容2

再来看看用.net的委托来如何实现:
using System;

namespace TemplateMethod
{
    
/// <summary>
    
/// TemplateMethod 的摘要说明。
    
/// </summary>

    public class TemplateMethod
    
{
        
public TemplateMethod()
        
{

        }

        
public delegate float Comp(float a,float b);
        
public Comp myComp;
        
public float DoComp(float[] f)
        
{
        
float nf=float.NaN;
            
foreach(float df in f)
            
{
                
if (float.IsNaN(nf))
                
{
                    nf
=df;
                }

                
else
                
{
                nf
=myComp(nf,df);
                }

                
            }
return nf;
        }

    }

}

      在DoComp类中我们定义与上面的委托相同的方法,这个类与TemplateMethod无关,只是其中方法的参数签名和返回值与上面的代理相同。如此,比较原来的实现方法,是不是少了上面那个继承的环节,实际上消除了原来的泛化关系,自然实现了抽象类和具体类的退藕(虽然此时已看不到任何泛化关系)。所以,我认为只要利用好.NET中的委托(.NET独有的特性)和反射可以大大加强软件的抽象和面向对象性,各位如果从前有比较好的面向对象基础,想必好好研究委托和反射对你的.NET 学习将大有俾益:
using System;

namespace TemplateMethod
{
    
/// <summary>
    
/// DoComp 的摘要说明。
    
/// </summary>

    public class DoComp
    
{
        
public DoComp()
        
{
        }

        
public float c1(float a,float b)
        
{
            
return a+b;
        }

        
public float c2(float a,float b)
        
{
            
return a*b;
        }

    }

}


好处就是使用时可以动态组装(我认为):
using System;

namespace TemplateMethod
{
    
/// <summary>
    
/// Class1 的摘要说明。
    
/// </summary>

    class Class1
    
{
        
/// <summary>
        
/// 应用程序的主入口点。
        
/// </summary>

        [STAThread]
        
static void Main(string[] args)
        
{
            TemplateMethod tm
=new TemplateMethod ();
            
float[] f={1,2,3,4};
            DoComp c
=new DoComp ();
            tm.myComp 
+=new TemplateMethod .Comp (c.c1 );
            System.Console .WriteLine (tm.DoComp (f).ToString ());
            tm.myComp 
-=new TemplateMethod .Comp (c.c1 );
            tm.myComp 
+=new TemplateMethod .Comp (c.c2 );
            System.Console .WriteLine (tm.DoComp (f).ToString ());
            System.Console .ReadLine ();
        }

    }

}

结果显示:
10
24
    这种方法可以说是模版方法的变相使用,但无疑达到了退藕的作用。但它比原来的方法也有它的缺点,就是如果在方法中涉及到对象的状态,这种方法则不太好用了,因为状态需要继承关系去维护,我们在此消灭了继承自然无法维护状态。

另:大家如果对下面的代码输出结果的
10
24
有任何疑惑的地方,建议下载代码后设断点调试一下,那样对整个过程会有比较清晰的了解。