Абстрактные классы в C#
Абстрактные классы
В предыдущих статьях (sealed классы в C# и статические классы в C#) я рассказывал про достаточно специфические классы, это классы, которые не могут быть использованы в качестве базовых классов (это sealed классы) и классы, объекты которых нельзя создавать в своих программах (это статические классы, хотя, они и в наследовании участия принимать тоже не могут). Так вот в этой статье, я хочу рассказать о еще одном типе классов, это абстрактные классы.
Абстрактные классы, тоже имеют ряд особенностей. Их объекты нельзя создавать (как и в случае статических классов), но предназначены абстрактные классы, именно для того, чтобы служить базовыми для других (т.е. полная противоположность sealed классам).
Таким образом, без механизма наследования, абстрактные классы практически бессмысленны!
А теперь, давайте разберемся подробнее, для чего же нужны абстрактные классы… Дело в том, что когда программист продумывает иерархию классов, на её вершине оказывается самый обобщенный класс. Возьмем для примера иерархию классов из урока № 22 базового курса C#:
//Базовый класс, описывающий оружие class Weapon { //Атака оружием public void Attack() { Console.WriteLine("Weapon Attack!"); } } //Класс-наследник оружия, описывает нож class Knife : Weapon { //Атака ножом public void Attack() { Console.WriteLine("Knife Attack!"); } } //Класс-наследник оружия, описывает ружьё class Gun : Weapon { //Атака ружьем public void Attack() { Console.WriteLine("Gun Attack!"); } }
Как видно, в приведенном примере есть три класса, на вершине иерархии находится класс «Weapon» (некое абстрактное оружие), а его наследниками, являются классы «Knife» (нож) и «Gun» (ружье), вполне себе конкретные классы. Так вот класс «Weapon» действительно представляет собой некое абстрактное оружие, и совсем непонятно, как должна выглядеть атака этим оружием… Создавать объекты этого класса нет никакого смысла, да и метод «Attack» нужно бы сделать виртуальным! Т.е. приведенный выше пример явно нуждается в доработке. И сейчас я покажу как это можно сделать.
А поступим мы так, класс «Weapon» мы сделаем абстрактным, и метод «Attack» в нем тоже будет абстрактным, у него не будет тела, т.е. реализации, так как мы действительно и не знаем что он должен делать в контексте класса «Weapon«. Плюс ко всему, метод «Attack» автоматически станет виртуальным, и в классах наследниках, мы его просто переопределим. Вот так это будет выглядеть на практике:
//Базовый класс, описывающий оружие (теперь абстрактный) abstract class Weapon { //Атака оружием public abstract void Attack(); } //Класс-наследник оружия, описывает нож class Knife : Weapon { //Атака ножом (теперь переопределенный метод, добавили override) public override void Attack() { Console.WriteLine("Knife Attack!"); } } //Класс-наследник оружия, описывает ружьё class Gun : Weapon { //Атака ружьем (теперь переопределенный метод, добавили override) public override void Attack() { Console.WriteLine("Gun Attack!"); } }
Всё довольно просто, изменения уложились в несколько строк (они выделены). Мы сделали класс «Weapon» абстрактным (добавили ключевое слово abstract перед его объявлением), так же сделали абстрактным метод «Attack» этого класса, а в классах наследника переопределили его (добавив ключевое слово override). И что мы получили в результате? Мы убрали всю конкретику (которая была не нужна) из класса «Weapon«, запретили создавать объекты этого класса (которые в принципе бессмысленны), сделали метод «Attack» автоматически виртуальным (объявив его абстрактным). Таким образом, мы убрали «всё ненужное» из первоначального примера и добились необходимого результата, используя абстрактный класс.
Зачем нужны виртуальные методы рассказывается в уроке № 22 базового курса.
В завершение, хочу отметить, что если в классе наследнике, не переопределить абстрактные сущности (в нашем случае, метод «Attack») базового класса, то класс наследник тоже придется делать абстрактным (и объекты этого класса мы создавать не сможем).
И еще один момент, эту же задачу, можно решить без применения абстрактных классов, используя вместо этого интерфейсы, пример и теория приведены в уроке № 24 базового курса. А о том, какой подход лучше, или скажем так, какие плюсы и минусы есть у обоих подходом, я расскажу в отдельной статье.
Добавить комментарий
Для отправки комментария вам необходимо авторизоваться.