上一篇文章讲了适配器Adapter模式。

这一次讲讲模版Template,其实这一章挺简单的,

当你使用了继承,那你就用了模板方法,只是你可能不知道这个就叫做模板方法。

其实模板方法的核心就是把实际的处理交给子类处理。

好吧,既然这样,模板方法也没有什么好说的了,

我们就来复习一下c#中的一些关于模板的语法,以及一些问题。在以后的面试中,很可能会考的到的哦。哥们儿我就遭遇了无数这种问题。

首先,我们来看看abstract关键字。

abstract可以用来修饰类、方法、属性、索引器及事件。不过我们常见的是用来修饰类和方法。

abstract用来修饰类:

public abstract class Animal,当我们尝试执行下面语句的时候:

Animal animal = new Animal();

编译器会报以下错误:

无法创建抽象类或接口“Template.Animal”

j结论:abstract 类只能是其他类的基类。

abstract用来修饰方法:

我们在抽象类Animal中,添加一个抽象的方法。

public abstract class Animal
{
      public abstract string Eat();
}

编译,通过。

 

我们把定义修改一下,去掉Animal之前的abstract:

 public class Animal
{
      public abstract string Eat()

     {

          return;

     }
}

编译,报错:

错误 1 “Template.Animal.Eat()”无法声明主体,因为它标记为 abstract 

结论:抽象方法不能声明主体,用于在子类中继承实现。

 

我们把定义修改一下,去掉Animal之前的abstract:

 public class Animal
{
      public abstract string Eat();
}

编译,报错:

“Template.Animal.Eat()”是抽象的,但它包含在非抽象类“Template.Animal”中 

结论:抽象方法之内包含在抽象类中。

 

我们再做一个修改,去掉Eat()前的public属性,默认为private:

 public abstract class Animal
{
      abstract string Eat();
}

编译,报错:

“Template.Animal.Eat()”: 虚拟成员或抽象成员不能是私有的

再修改成protected,编译通过。

结论:虚方法必须是public 或者 protected的.这个是因为abstract 是基类需要继承,如果abstract 方法是私有的话,那子类是不能继承的,所以abstract 和 private同时修饰方法没有丝毫意义。

 

我们用一个Dog类去继承Animal:

public  class Dog : Animal
{

}

编译,报错:

“Template.Dog”不实现继承的抽象成员“Template.Animal.Eat()”

结论:子类必须要实现抽象类的抽象成员

 

我们现在来实现这个Eat()成员:

public  class Dog : Animal
    {
        public string Eat()
        {

            return "I eat bone";
        }
    }

编译,一个错误,一个警告:

警告 1 “Template.Dog.Eat()”将隐藏继承的成员“Template.Animal.Eat()”。若要使当前成员重写该实现,请添加关键字 override。否则,添加关键字 new。

错误 2 “Template.Dog”不实现继承的抽象成员“Template.Animal.Eat()”

ok,我们加上override,编译通过。

结论:我们必须要通过override关键字来实现被abstract修饰的父类函数的主体。


如果我们的Dog也是一个abstract 那情况又会如何呢?

上面我们说过了,子类必须要实现抽象类的抽象成员

但实际上

public abstract  class Dog : Animal
{
}

编译是可以通过的!!!!

这个是为什么呢?

实际上,上面的写法等同于:

public abstract  class Dog : Animal
{

     public override abstract string Eat();

}

那么我们只要想实例化这个类,我们总会有一个类会对它的Eat()方法进行实现。

 

好了,我们再假如Animal不是abstract类型的,那么根据上面所说,它的Eat成员是必须实现的:

 public class Animal
{
      public string Eat()

     {

          return "I eat nothing";

     }
}

我们在用Dog继承的时候应该怎么修改Eat()方法呢?

我们试试这样:

public class Dog : Animal
    {
        public string Eat()
        {
            return "I eat bone";
        }
    }

编译,一个警告:

警告 1 “Template.Dog.Eat()”隐藏了继承的成员“Template.Animal.Eat()”。如果是有意隐藏,请使用关键字 new。
很明显,我们应该用new关键字去隐藏父类的方法。

public class Dog : Animal
    {
        public new string Eat()
        {
            return "I eat bone";
        }
    }

编译通过。

可是我们用main函数调用一下呢,

            Animal dog = new Dog();
            System.Console.WriteLine(dog.Eat());
输出是:

I eat nothing

这和我们期望的不一样呢。

那正确的写法是什么呢?ok,我们现在引入virtual关键字

virtual可以用来修饰方法、属性、索引器及事件。virtual不能用于修饰类,这个与abstract不同。

接着我们测试:

public class  Animal
{

     public virtual string Eat();

}

编译,错误:

错误 1 “Template.Animal.Eat()”必须声明主体,因为它未标记为 abstract、extern 或 partial 

结论:被virtual必须要实现主体。

继续:

public class Animal
    {
        public virtual string Eat()
        {
            return "I eat noting";
        }
    }

    public class Dog : Animal
    {
        public string Eat()
        {
            return "I eat bone";
        }
    }

编译,一个警告:

警告 1 “Template.Dog.Eat()”将隐藏继承的成员“Template.Animal.Eat()”。若要使当前成员重写该实现,请添加关键字 override。否则,添加关键字 new。 

测试输出一下:

            Animal dog = new Dog();
            System.Console.WriteLine(dog.Eat());

依然是输出:

I eat noting

结论:在父类中用virtual声明的方法,在子类中必须用override进行重写。

所以最后正确的写法是:

public class Animal
    {
        public virtual string Eat()
        {
            return "I eat noting";
        }
    }

    public class Dog : Animal
    {
        public override string Eat()
        {
            return "I eat bone";
        }
    }

测试:

            Animal dog = new Dog();
            System.Console.WriteLine(dog.Eat());

输出:

I eat bone

 

ok.写到这里,大家应该都比较明白了吧:),相信仔细研究一下,就不会在这个问题上在面试主考官那里卡壳了。