Рубрики
Без рубрики

Абстракция и инкапсуляция – [ООП и Java #1]

Примечание: Эта серия предназначена для моего пересмотра содержания и консолидации обучения. Публикую это здесь… С пометкой “информатика”, java, ооп, codenewbie.

ООП и Java (Серия из 14 частей)

Примечание: Эта серия предназначена для моего пересмотра содержания и консолидации обучения. Публикую это здесь, потому что мне нравится подсветка кода РАЗРАБОТЧИКА. Присоединяйтесь ко мне, если хотите освежить свою память об ООП и Java.
ВСТУПЛЕНИЕ (Некоторые основы Java)
  • В отличие от Python, Java должна быть скомпилирована перед запуском
  • Знание типов является обязательным при написании программ на Java
  • Java фокусируется на объектно-ориентированном моделировании, где все находится в пределах некоторых классов
  • Модель памяти Java: Стек для выполнения функций, куча для хранения объектов и сбора мусора, Не куча (метапространство) для статических полей и т.д.
ООП

Я думаю, что есть несколько ключевых моментов в ООП, которые отличаются от стандартного процессно-ориентированного способа написания кода:

  • Моделируйте свой код на основе реальных объектов
  • Все остальное – это взаимодействие между объектами

Предположим, мы хотим выяснить, находится ли точка внутри круга, что нам делать? Базовые знания в области программирования говорят нам, что нам нужно написать алгоритм или, точнее, функцию, описывающую процедуры, которым будет следовать компьютер. Допустим, мы сделаем следующее:

boolean contains(double pointX, double pointY, double centreX, double centreY, double radius){
    // by distance between two points on a graph formulae
    double dx = pointX - centreX;
    double dy = pointY - centreY;
    double distance = math.sqrt(dx*dx + dy*dy); 
    return distance < radius;
}

Это сработает, но можем ли мы сделать лучше?

Первое наблюдение состоит в том, что существует пять параметров. Вы хотите использовать функцию, возможно, написанную другими, которая требует от вас ввода 5 различных параметров в определенном порядке? Это определенно подвержено ошибкам, и пользователь должен выяснить, какое двойное значение куда идет. Итак, Абстракция данных на помощь.

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

class Point {
    double x;
    double y;
}
class Circle {
    Point centre;
    double radius;
}
boolean contains(Point p, Circle c){
    double dx = p.x- c.x;
    double dy = p.y- c.y;
    double distance = math.sqrt(dx*dx + dy*dy); 
    return distance < c.radius;
}

Теперь, если мы дадим кому-то вышеупомянутую функцию, у него будет меньше шансов совершить ошибки. Здесь я приравниваю абстракцию данных к:

Уменьшите и сделайте бессмысленные параметры значимыми

Вместо того, чтобы передавать простые фрагменты данных, теперь через нашу программу проходят интеллектуальные вещи, которые знают тебя самого. Кроме того, обратите внимание, что наша программа фактически увеличилась в размерах. Абстракция – это более эффективная организация кода, чем простое удаление.

Следующий логический скачок заключается в том, что функция “содержит” слишком многословна. Как мы могли бы разбить его дальше? Обратите внимание, что слово “содержит” говорит о том, находится ли что-то внутри другой вещи. То, что мы делаем в этой функции, – это нечто большее. Мы вычисляем расстояние между двумя точками, затем спрашиваем, меньше ли расстояние радиуса. Расчет расстояния не является “содержит”. Мы могли бы убрать его вот так:

boolean contains(Point p, Circle c){
    double d = distance(p,c.centre);
    return d

Теперь обе функции работают точно так же, как и то, в честь чего они названы:

  • distance() возвращает расстояние
  • содержит() возвращает значение true или false

Это функциональная абстракция , на которую я говорю:

Сократите и сделайте бессмысленные строки кода значимыми

Идея инкапсуляции возникла потому, что наш код похож на голого мужчину. Возможно, нам захочется надеть какую-нибудь одежду по двум причинам, чтобы люди не видели и не прикасались к ней.

В приведенном выше примере мы используем два числа для представления координат. Но кто-то может изменить представление на использование массива. Это знание слишком низкого уровня и опасное, потому что оно подвержено изменениям.

Подобно тому, как у нас есть брюки для вашей нижней части тела и рубашки для верхней части тела, мы упаковываем данные в классы на Java. Один из важнейших вопросов заключается в том, где мы упаковываем функции, которые работают с этими данными. Если мы помним, что мы моделируем вещи как объекты реальной жизни, то мы можем ответить на этот вопрос, сказав, что функция может быть сохранена с той, которая выполняет действие, или с той, которая получает действие, или и с той, и с другой.

Причина, по которой мы избегаем этого в обоих местах, очевидна:

  • ненужный код
  • предотвращать взаимозависимость

Следовательно, большую часть времени мы должны помещать соответствующие функции в разумные классы. Если вы закодировали вызов функции “содержит”, возможно, имеет смысл поместить его в класс Circle, поскольку круг содержит точку.

class Point{
    double x;
    double y;
    double distance(Point b){
        double dx = this.x- b.x;
        double dy = this.y- b.y;
        return math.sqrt(dx*dx + dy*dy); 
    }
}
class Circle {
    Point centre;
    double radius;
    boolean contains(Point p, Circle c){
        double d = p.distance(c.centre);
        return d

Вторая часть истории – предотвращение контакта. В Java у нас есть модификаторы доступа, такие как общедоступный и private запретить изменение значений переменных экземпляра в одном классе из другого класса.

class Impt {
    private int x;
    void changeSelf(){ // acceptable
        x=1;
    }
    void changeOther(Impt p){ // acceptable
        p.x = 1;
    }
}

class Client {
    void change(Impt p){ // illegal access
        p.x =1;
    }
}      

Одно замечание о частном доступе:

Это означает доступ на уровне класса, а не доступ на уровне объекта. Следовательно, функция в классе может получить доступ к внутренним элементам экземпляра того же класса, даже если она помечена как закрытая. Вы также можете думать об этом как о реализованных объектах одного и того же типа. Это не отношения между клиентом и исполнителем. Следовательно, в двух реализованных системах нет барьера абстракции. См. Сообщение о переполнении стека для получения дополнительной информации:

class Person
{
   private BankAccount account;

   Person(BankAccount account)
   {
      this.account = account;
   }

   public Person someMethod(Person person)
   {
     //Why accessing private field is possible?

     BankAccount a = person.account;
   }
}

Пожалуйста, забудьте о дизайне. Я знаю, что ООП указывает, что частные объекты являются частными для класса. Мой вопрос…

Последние две концепции несколько новы для меня, и поэтому я хотел бы изложить свои мысли по каждой из них.

Скажи-Не-Спрашивай

Указывать объекту, что делать, вместо того, чтобы запрашивать у объекта данные и действовать в соответствии с ними.

boolean contains(Point p, Circle c){
// tell a point to give me distance
    double d = p.distance(c.centre);
    return d

Важно понимать эту концепцию в контексте взаимодействия объектов. Следуя приведенному выше примеру, метод “содержит” в классе Circle не будет запрашивать координаты точки и вычислять их. Он предпочтет, чтобы расстояние вычислялось по классу точек и возвращалось для сравнения.

Неизменность

следует избегать методов void, которые изменяют состояния

Point setX(double x){
// does not mutate the original point
    return new Point(x, this,y);
}
// vs
void setX(double x){
// mutates the original point
    this.x = x;
}

Это делается для обеспечения последовательности в тестировании.

Для меня эти два принципа в основном препятствуют использованию геттеров и сеттеров. Я думаю, что, вероятно, есть какая-то ситуация, когда сеттеры и геттеры полезны.

Резюме

Абстракция

  • Абстракция данных
  • Абстракция функций

Инкапсуляция

  • Упаковка
  • Сокрытие информации

Принцип хорошего проектирования ООП

  • Скажи-Не-Спрашивай
  • Неизменность

ООП и Java (Серия из 14 частей)

Оригинал: “https://dev.to/tlylt/abstraction-and-encapsulation-oop-java-1-11jm”