继承:
作为面向对象三大特性之一的继承,功能不是一般的强大,在书的344页《大话设计模式》我们可以看到Cat和Dog类代码内容基本形同,只是在叫的时候发出的声音不同罢了,如果现在我们要添加别的动物,比如兔子,猪...等等,则需要写相同的代码(复制)只是改改各自的叫声罢了。
我们知道一条编程的原则就是尽可能的避免重复,比较四个类,可以抽象出animal这个类作为父类把相同的代码放在父类中,然后子类通过多态实现对叫声Shout()方法的重写实现各自的叫声。
继承的好处:子类拥有父类非private的属性和功能;子类是父类的特殊化;子类可以对父类的方法进行重写。
模板方法模式:
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即了重新定义该算法的某些特定步骤。
说白了就是几个类的主要代码基本相同,只是个别步骤的算法不同。我们用模板模式对代码进行重构。
以老师在黑板上抄题,学生抄写题目并写出相应的答案为例。
代码结构图
//学生甲的试卷
ClassTestPaperA
{
//试题1
public void TestQuestion1()
{
Console.WriteLine("2+1=[ ] a.0 b.1 c.2 d.3")
Console.WriteLine("答案:c")
}
//试题2
public vodi TestQuestion2()
{
Console.WriteLine("2-1= [] a.0 b.1 c.2 d.3")
Console.WriteLine("答案:c")
}
//试题3
public vodi TestQuestion3()
{
Console.WriteLine("2*1= [] a.0 b.1 c.2 d.3")
Console.WriteLine("答案:c")
}
}
//学生乙的试卷
ClassTestPaperA
{
//试题1
public void TestQuestion1()
{
Console.WriteLine("2+1=[ ] a.0 b.1 c.2 d.3")
Console.WriteLine("答案:d")
}
//试题2
public vodi TestQuestion2()
{
Console.WriteLine("2-1= [] a.0 b.1 c.2 d.3")
Console.WriteLine("答案:d")
}
//试题3
public vodi TestQuestion3()
{
Console.WriteLine("2-1= [] a.0 b.1 c.2 d.3")
Console.WriteLine("答案:d")
}
}
比较甲乙抄写试卷的代码我们知道,试卷中的试题是相同的不同的只是甲乙各自的答案Console.WriteLine("")不同。确切的说是输出的答案(a.b.c.d)不同,而Console.WriteLine()方法还是子类所共有的。
我们已经知道重复的危害,容易出错,而且在修改的时候很困难。所以下面我们要做的就是提炼代码,将相同的代码提到一个共有的父类中。
优化后
代码结构图
父类
<span style="font-size:14px;">class TestPaper
{
//试题1
public void TestQuestion1()
{
Console.WriteLine("2+1=[ ] a.0 b.1 c.2 d.3")
Console.WriteLine("答案:+ Answer1()") /Answer1()是个虚方法,
}
protected virtual stringAnswer1() /让子类重写该方法
{
return ""
}
}
//试题2
public vodi TestQuestion2()
{
Console.WriteLine("2-1= [] a.0 b.1 c.2 d.3")
Console.WriteLine("答案:+ Answer2()")
}
protected virtual string Answer2()
{
return ""
}
//试题3
public vodi TestQuestion3()
{
Console.WriteLine("2*1= [] a.0 b.1 c.2 d.3")
Console.WriteLine("答案:+ Answer3()")
}
protected virtual string Answer()
{
return ""
}</span>
子类的代码
<span style="font-size:14px;">//甲类
classTestPaperA : TestPaper
{
protected override string Answer1
{
return c;
}
protected override string Answer2
{
return c;
}
protected override string Answer3
{
return c;
}
}</span>
乙类代码和甲类相同只是在输出答案的时候不同。
客户端代码:
<span style="font-size:14px;">static void Main(string[] args)
{
Console.WriteLine("学生甲抄的试卷:");
TestPaper studentA = new TestPaperA();
studentA.TestQusetion1();
studentA.TestQusetion2();
studentA.TestQusetion3();
Console.WriteLine("学生乙抄的试卷:");
TestPaper studentB = new TestPaperA();
studentB.TestQusetion1();
studentB.TestQusetion2();
studentB.TestQusetion3();
}</span>
模板方法模式通过把不变的行为搬移到超类中去除了子类中的重复代码,提供了一个很好的代码复用平台。
总结:模板模式充分体现了继承的好处,通过提取不变的行为抽象为父类,从而简化的代码的重复,优化了系统的结构,是我们很常用的模式。