Объектно-ориентированное программирование (ООП) — это парадигма программирования, которая зависит от классов и объектов. Это помогает разработчикам программного обеспечения структурировать свои коды и делать их многократно используемыми частями.
Разработчики программного обеспечения создают для этого множество различных классов.
Классы — это определяемые пользователем типы данных, которые имеют свои собственные атрибуты и методы. Эти методы могут определять логические операции класса. А атрибуты могут содержать данные, которые может иметь класс.
Мы можем создать столько экземпляров класса, сколько захотим. Эти экземпляры называются объектами.
Концепции объектно-ориентированного программирования
Объектно-ориентированное программирование имеет четыре основных понятия. Эти концепции могут показаться вам немного сложными, если вы не были знакомы с ними раньше. Но понимание того, как работают эти концепции, может очень помочь вам в вашей карьере разработчика программного обеспечения.
Инкапсуляция
Инкапсуляция означает, что атрибуты класса скрыты от любого другого класса и доступны только через любые методы-члены собственного класса, в которых объявлены атрибуты.
Для этого мы можем определить атрибуты как закрытые. Затем мы можем добавить методы getter-setter как общедоступные для атрибута.
Существует 3 типа видимости для переменных и методов. Это:
- общедоступный: если переменные или методы определены как общедоступные, к ним можно получить доступ из любого другого класса путем создания экземпляра.
- private: Если переменные или методы определены как private, к ним можно получить доступ только в классе, в котором мы определили переменные или методы.
- защищено. Если переменные или методы определены как защищенные, к ним можно получить доступ только из класса, в котором были определены переменные или методы, или из других классов, которые были расширены из этого класса и имеют переменные или методы.
Я приведу вам пример инкапсуляции. Но нам не нужно беспокоиться об инкапсуляции в Kotlin. Я объясню причину после того, как приведу пример кода:
class EncapsulationExample { private var testString: String = "" private var testInteger: Int = 0 }
Нам не нужно беспокоиться об инкапсуляции в Kotlin. Потому что компилятор Kotlin для JVM компилирует исходные файлы Kotlin в файлы классов Java. Таким образом, наш код будет скомпилирован следующим образом:
Примечание: Имя класса не изменится. Я изменил его, чтобы сделать его более понятным.
public class EncapsulationCompiled { private String testString = ""; private int testInteger = 0; public String getTestString() { return testString; } public void setTestString(String testString) { this.testString = testString; } public int getTestInteger() { return testInteger; } public void setTestInteger(int testInteger) { this.testInteger = testInteger; } }
Абстракция
Абстракция — это процесс сокрытия внутренних деталей класса от внешнего мира.
Мы можем определять абстрактные методы или абстрактные классы. Если у одного класса есть хотя бы один абстрактный метод, это означает, что класс может быть абстрактным классом. Абстрактные классы обычно используются для сбора объектов с общими свойствами под одной крышей.
abstract class AbstractionExample{ abstract fun abstractMethod() fun methodWithBody(){ println("This method has a body.") } }
Но, если все методы абстрактные и нет ни одного метода с телом, значит это интерфейс.
interface InterfaceExample { fun methodOne() fun methodTwo() }
Наследование
Наследование означает, что один класс приобретает атрибуты и методы другого класса. Это означает, что мы можем создавать новые классы поверх существующих классов.
Основная цель наследования — обеспечить возможность повторного использования кода. Итак, класс должен писать только уникальные атрибуты и методы. Остальные общие атрибуты и методы могут быть расширены из другого класса.
Здесь появляются два новых термина. Родительский класс и дочерний класс.
- Родительский класс. Это класс, атрибуты и методы которого будут использоваться дочерним классом.
- Дочерний класс. Это класс, который расширяет возможности родительского класса.
Примечание. Если мы хотим создать расширяемый класс (родительский класс) в Kotlin, мы должны добавить ключевое слово «open» перед ключевым словом «class». В противном случае мы не сможем расширить этот класс из других классов. Как и в случае с классами, если мы хотим переопределить метод в дочернем классе, мы должны добавить ключевое слово «open» перед ключевым словом «fun» в родительском классе.
open class InheritanceParentClass{ var attributeParentClass1 = "Attribute in Parent Class" private var attributeParentClass2 = "We can't reach this attribute in child class. Because we defined it as private" fun methodParentClass1() = "This is first method in InheritanceParentClass" open fun methodParentClass2() = "This is second method in InheritanceParentClass. We will override this one." }
Как мы узнали из раздела «Инкапсуляция», мы не можем получить доступ к атрибутам или методам в дочернем классе, которые определены как закрытые в родительском классе. Поэтому, если мы хотим, чтобы их можно было использовать в дочернем классе, мы не должны добавлять ключевое слово private.
class InheritanceChildClass: InheritanceParentClass() { fun methodChildClass1() = "This is first method in InheritanceParentClass" override fun methodParentClass2() = "This method has overridden in child class" fun printAttributeParentClass1(){ println("$attributeParentClass1") attributeParentClass1 = "Attribute in Child Class" println("$attributeParentClass1") } }
Я дам очень простой основной метод для печати этих методов.
fun main(){ var parentClass = InheritanceParentClass() var childClass = InheritanceChildClass() println("Parent Class - methodParentClass1: ${parentClass.methodParentClass1()}") println("Parent Class - methodParentClass2: ${parentClass.methodParentClass2()}") println("Child Class - methodChildClass1: ${childClass.methodChildClass1()}") println("Child Class - methodParentClass2: ${childClass.methodParentClass2()}") childClass.printAttributeParentClass1() }
Вывод:
Parent Class - methodParentClass1: This is first method in InheritanceParentClass Parent Class - methodParentClass2: This is second method in InheritanceParentClass. We will override this one. Child Class - methodChildClass1: This is first method in InheritanceParentClass Child Class - methodParentClass2: This method has overridden in child class Attribute in Parent Class Attribute in Child Class
Полиморфизм
С помощью полиморфизма мы можем выполнять одно и то же действие по-разному. Для этого нам нужно определить один интерфейс, класс или абстрактный класс, и у нас будет несколько реализаций.
Я приведу краткий пример. Вы увидите, что с помощью полиморфизма метод может выполнять различные операции в зависимости от объекта, над которым он действует.
Во-первых, у нас будет родительский класс под названием «PolymorphismBaseClass».
open abstract class PolymorphismBaseClass { open fun runMobileServiceOnDevice(){ println("This device is not running any mobile services.") } abstract fun mobileServicesName(): String }
Затем мы можем создать дочерние классы из этого родительского класса. Наши дочерние классы будут использовать тот же метод. Эти методы будут выполнять разные, но похожие операции.
class PolymorphismHuaweiClass: PolymorphismBaseClass() { override fun runMobileServiceOnDevice() { println("This device can work with Huawei Mobile Services.") } override fun mobileServicesName(): String = "Huawei Mobile Services" } class PolymorphismGoogleClass: PolymorphismBaseClass() { override fun runMobileServiceOnDevice() { println("This device can work with Google Mobile Services.") } override fun mobileServicesName(): String = "Google Mobile Services" }