Showing posts with label ООП. Show all posts
Showing posts with label ООП. Show all posts

Friday, December 10, 2010

Наследование классов (часть 2)

Итак, у нас два класса – Door и Window и базовый для них BaseObject (см часть 1). В базовом классе есть методы Open и Close.
class BaseObject
{
    private bool isOpened;
    public void Open()
    {
        isOpened = true;
    }
    public void Close()
    {
        isOpened = false;
    }
}

class Door : BaseObject
{
}

class Window : BaseObject
{
}

Мы знаем еще, что для Door при открытии и закрытии нужны дополнительные действия (т.е. методы) – открыть и закрыть дверь ключом (OpenByKey, CloseByKey). Добавить их не сложно:
class Door : BaseObject
{
    public void OpenByKey()
    {
    }
    public void CloseByKey()
    {
    }
}

Проблема будет в том, что при вызове метода Open нужно не забыть вызвать метод OpenByKey, иначе к нам заберутся воры J Ну а там где есть слово “нужно не забыть” – забудут наверняка, тем более, что не понятно, как подсказать программисту, использующему наш класс, что этот вызов вообще нужен.
Хорошо бы иметь свою реализацию метода Open, такую, что в ней уже вызывается работа с ключом. Получается, что с одной стороны, мы хотим использовать базовый класс и его реализацию, чтобы не дублировать код. С другой – иметь собственную реализацию этого метода.
Оказывается, сделать это очень легко – для этого используется перекрытие методов.
Метод в базовом классе мы должны обозначить как перекрываемый, добавив к нему слово virtual (метод будет называться виртуальным, но я пока не буду вдаваться в подробности почему):
class BaseObject
{
    private bool isOpened;
    public virtual void Open()
    {
        isOpened = true;
    }
    public virtual void Close()
    {
        isOpened = false;
    }
}

А в классе наследнике мы должны будем обозначить, что мы перекрываем метод базового класса. Для этого используется слово override:
class Door : BaseObject
{
    public override void Open()
    {
        base.Open();
        OpenByKey();
    }

    public override void Close()
    {
        base.Close();
        CloseByKey();
    }

    private void OpenByKey()
    {
    }
    private void CloseByKey()
    {
    }
}

Обратите внимание на две вещи. Во-первых, на вызов base.Open и base.Close в перекрытых методах. Это означает, что мы вызываем методы базового класса. И, во-вторых, методы работы с ключом я сразу же сделал закрытыми (private), т.к. больше нет необходимости вызывать их самостоятельно – все будет сделано внутри классов.

Tuesday, December 7, 2010

Наследование классов (часть 1)

Предположим, что у нас есть два объекта – Door (дверь) и Window (окно). Каждый из них имеет методы Open (открыть) и Close (закрыть):
Class Door
{
  private bool isOpened;
  public void Open()
  {
    isOpened=true;
  }
  public void Close()
  {
    isOpened=false;
  }
}
Точно такой же код содержится в классе Window. Проблема именно в “точно такой же” – при необходимости модифицировать этот код нам придется найти все его вхождения и исправить. Не факт что мы найдем все.
Наследование позволяет, во-первых, избавиться от дублирования кода, вынести его в общее место.
class BaseObject
{
  private bool isOpened;
  public void Open()
  {
    isOpened=true;
  }
  public void Close()
  {
    isOpened=false;
  }
}
class Door : BaseObject
{
  // методы Open и Close доступны
  // они придут сюда из базового объекта
}
class Window : BaseObject
{
}
Во-вторых, наследование выстраивает логические связи между объектами, облегчая их понимание. Вместо кучи разрозненных классов, мы получаем осмысленную структуру (иерархию классов). Разумеется, эта иерархия должна отражать логические связи, иначе, она будет не понятна. Например, класс Бутылка тоже может иметь методы Открыть и Закрыть, но наследовать его от базового объекта СтроительныеМатериалы, не очень логично.
Класс BaseObject, от которого происходит наследование, называется базовым классом.
Классы Door и Window называются наследниками (потомками) класса BaseObject.
Замечу, что в C++ и многих других языках, можно было реализовать класс, наследующий несколько классов, но в C# такую возможность закрыли. Сделали это специально, т.к. множественное наследование вызывало ошибки.
В C# абсолютно все типы наследуются от специального типа System.Object.
Итак, первые два плюса наследования:
1. Сокращение дублирования кода
2. Создание логических связей между объектами.
Продолжение следует.