oop учебник
Начало работы с oop
Поиск…
замечания
Объектно-ориентированное программирование (ООП) - это парадигма программирования, основанная на концепции «объектов», которая может содержать данные, в виде полей, часто называемых атрибутами; и код, в виде процедур, часто известных как методы.
Вступление
ООП - объектно-ориентированное программирование - это широко используемая парадигма программирования в наши дни. В ООП мы моделируем проблемы реального мира с использованием объектов и там поведения, чтобы их решить, программно.
Существует четыре основных концепции ООП
- наследование
- Полиморфизм
- абстракция
- Инкапсуляция
Эти четыре концепции вместе используются для разработки программ в ООП.
Существуют различные языки, которые поддерживают программно-ориентированное программирование. Самые популярные языки
- 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 ключевом слове указано, что вы не можете переопределить этот метод при наследовании этого класса. Если класс объявлен окончательным, то ни один класс не может наследовать его вообще.