Поиск…


замечания

Объектно-ориентированное программирование (ООП) - это парадигма программирования, основанная на концепции «объектов», которая может содержать данные, в виде полей, часто называемых атрибутами; и код, в виде процедур, часто известных как методы.

Вступление

ООП - объектно-ориентированное программирование - это широко используемая парадигма программирования в наши дни. В ООП мы моделируем проблемы реального мира с использованием объектов и там поведения, чтобы их решить, программно.

Существует четыре основных концепции ООП

  1. наследование
  2. Полиморфизм
  3. абстракция
  4. Инкапсуляция

Эти четыре концепции вместе используются для разработки программ в ООП.

Существуют различные языки, которые поддерживают программно-ориентированное программирование. Самые популярные языки

  • C ++
  • Джава
  • C #
  • Python (Python не полностью Object Oriented, но имеет большинство функций OOP)

Введение в ООП

презентационное

Объектно-ориентированное программирование (в основном называемое ООП) - это парадигма программирования для решения проблем.
Красота программы OO (объектно-ориентированная) заключается в том, что мы рассматриваем программу как совокупность объектов, обменивающихся друг с другом, а не как последовательный скрипт, выполняющий определенные заказы.

Есть много языков программирования, которые поддерживают ООП, некоторые из популярных:

  • Джава
  • C ++
  • C #

Известно, что Python поддерживает ООП, но ему не хватает нескольких свойств.


Терминология ООП

Самый простой термин в ООП - это класс .
Класс - это в основном объект , который имеет состояние и работает в соответствии с его состоянием.

Другим важным термином является экземпляр .
Подумайте о классе как шаблоне, используемом для создания экземпляров самого себя. Класс - это шаблон, а экземпляр (ы) - это конкретные объекты.

Экземпляр, созданный из класса A , обычно упоминается как «тип A», точно так же, как тип 5 является int, а тип «abcd» - это строка .

Пример создания экземпляра с именем insance1 типа (класса) ClassA :

Джава

ClassA instance1 = new ClassA();

C ++

ClassA instance1;

или же

ClassA *instance1 = new ClassA(); # On the heap

питон

instance1 = ClassA()

Как вы можете видеть в приведенном выше примере, во всех случаях упоминалось имя класса, а после него были пустые круглые скобки (кроме C ++, если они пусты, скобки можно отбросить). В этих круглых скобках мы можем передать arguments конструктору нашего класса.

Конструктор - это метод класса, который вызывается каждый раз, когда создается экземпляр. Он может принимать аргументы или нет. Если программист не указывает какой-либо конструктор для создаваемого класса, будет создан пустой конструктор (конструктор, который ничего не делает).
В большинстве языков конструктор определяется как метод без определения его типа возврата и с тем же именем класса (пример из нескольких разделов).

Пример создания экземпляра с именем b1 типа (класса) ClassB . Конструктор ClassB принимает один аргумент типа int :

Джава

ClassA instance1 = new ClassA(5);

или же

int i = 5;
ClassA instance1 = new ClassA(i);

C ++

ClassA instance1(5);

питон

instance1 = ClassA(5)

Как вы можете видеть, процесс создания экземпляра очень похож на процесс вызова функции.


Функции против методов

Обе функции и методы очень похожи, но в объектно-ориентированном дизайне (OOD) каждый из них имеет свой собственный смысл.
Метод - это операция, выполняемая над экземпляром класса. Сам метод обычно использует состояние экземпляра для работы.
Между тем функция принадлежит классу, а не конкретному экземпляру. Это означает, что он не использует состояние класса или любые данные, хранящиеся в экземпляре.

Отныне мы покажем наши примеры только на Java, поскольку OOP очень ясен на этом языке, но одни и те же принципы работают на любом другом языке ООП.

В Java функция имеет слово static в своем определении, например:

// File's name is ClassA
public static int add(int a, int b) {
    return a + b;
}

Это означает, что вы можете вызвать его из любого места сценария.

// From the same file
System.out.println(add(3, 5));

// From another file in the same package (or after imported)
System.out.println(ClassA.add(3, 5));

Когда мы вызываем функцию из другого файла, мы используем имя класса (в Java это также имя файла), которому оно принадлежит, это дает интуицию, что функция принадлежит классу, а не его экземплярам.

Напротив, мы можем определить mehod в ClassA следующим образом:

// File's name is ClassA
public int subtract(int a, int b){
    return a - b;
}

После этого объявления мы можем вызвать этот метод следующим образом:

ClassA a = new ClassA();
System.out.println(a.subtract(3, 5));

Здесь нам нужно было создать экземпляр ClassA , чтобы вызывать его метод. Обратите внимание, что мы НЕ МОЖЕМ сделать следующее:

System.out.println(ClassA.subtract(3, 5));

Эта строка приведет к ошибке компиляции, вызванной тем, что мы назвали этот нестатический метод без экземпляра.


Использование состояния класса

Предположим, мы хотим снова реализовать наш метод вычитания , но на этот раз мы всегда хотим вычесть одинаковое число (для каждого экземпляра). Мы можем создать следующий класс:

class ClassB {

    private int sub_amount;

    public ClassB(int sub_amount) {
        this.sub_amount = sub_amount;
    }

    public int subtract(int a) {
        return a - sub_amount;
    }

    public static void main(String[] args) {
        ClassB b = new ClassB(5);
        System.out.println(b.subtract(3)); // Ouput is -2
    }
}

Когда мы запускаем этот код, создается новый экземпляр с именем b класса ClassB, а его конструктор получает значение 5 .
Конструктор теперь принимает данный sub_amount и сохраняет его как свое личное поле, также называемое sub_amount (это соглашение очень известно в Java, чтобы назвать аргументы такими же, как поля).
После этого мы печатаем на консоль результат вызова метода вычитаем из b со значением 3 .

Обратите внимание, что при реализации вычитания мы не используем this. как в конструкторе.
В Java this нужно только писать, когда есть другая переменная с тем же именем, определенным в этой области. То же самое работает с self Python.
Поэтому, когда мы используем sub_amount в вычитании, мы ссылаемся на частное поле, которое отличается для каждого класса.

Еще один пример подчеркнуть.
Давайте просто изменим основную функцию в приведенном выше коде на следующее:

ClassB b1 = new ClassB(1);
ClassB b2 = new ClassB(2);

System.out.println(b1.subtract(10)); // Output is 9
System.out.println(b2.subtract(10)); // Output is 8

Как мы видим, b1 и b2 независимы, и каждый из них имеет собственное состояние .


Интерфейсы и наследование

Интерфейс - это контракт, он определяет, какие методы будет иметь класс и, следовательно, его возможности. Интерфейс не имеет реализации, он только определяет, что нужно сделать.
Пример в Java:

interface Printalbe {
    public void print();
}

Интерфейс Printalbe определяет метод print, но он не дает его реализации (довольно странно для Java). Каждый класс, объявляющий себя как implementing этот интерфейс, должен обеспечить реализацию метода draw. Например:

class Person implements Printalbe {

    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void print() {
        System.out.println(name);
    }
}

Если Person объявит себя как реализующий Drawable, но не предоставит реализацию для печати , будет ошибка компиляции, и программа не будет компилироваться.

Наследование - это термин, который указывает на класс, расширяющий другой класс. Например, скажем, теперь у нас есть человек, у которого есть возраст. Одним из способов реализовать такого человека было бы скопировать класс Person и написать новый класс под названием AgedPerson, который имеет те же поля и методы, но имеет другое свойство -age.
Это было бы ужасно, поскольку мы дублируем весь наш код только для добавления простой функции в наш класс.
Мы можем использовать наследование для наследования от Person и, таким образом, получить все его функции, а затем улучшить их с помощью нашей новой функции, например:

class AgedPerson extends Person {

    private int age;

    public AgedPerson(String name, int age) {
        super(name);
        this.age = age;
    }

    public void print() {
        System.out.println("Name: " + name + ", age:" + age);
    }
}

Происходит несколько новых вещей:

  • Мы использовали сохраненное слово extends чтобы указать, что мы наследуем Person (а также его реализацию для Printable) , поэтому нам не нужно снова объявлять о implementing Printable .
  • Мы использовали save word super для вызова конструктора Person .
  • Мы переопределили метод печати Person с новым.

Это становится довольно техничным Java, поэтому я не буду углубляться в эту тему. Но я упомянул о том, что перед началом использования их необходимо узнать о крайних случаях, связанных с наследованием и интерфейсами. Например, какие методы и функции наследуются? Что происходит с закрытыми / общедоступными / защищенными полями при наследовании от класса? и так далее.

Абстрактный класс

Абстрактный класс - довольно продвинутый термин в ООП, который описывает комбинацию обоих интерфейсов и наследования. Это позволяет вам писать класс, в котором реализованы как реализованные, так и нереализованные методы / функции. В Java это делается с использованием abstract ключевого слова, и я не буду объяснять это скорее тем, что быстрый пример:

abstract class AbstractIntStack {

    abstract public void push(int element);

    abstract public void pop();

    abstract public int top();

    final public void replaceTop(int element) {
        pop();
        push(element);
    }
}

Примечание. В final ключевом слове указано, что вы не можете переопределить этот метод при наследовании этого класса. Если класс объявлен окончательным, то ни один класс не может наследовать его вообще.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow