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

Подробнее о Сеттере, Геттере и ООП

Это для бизнес-проектов. Архитектура Бизнес-объекта В прошлом наша дуга… Помеченный как java, архитектура, ооп.

Это для бизнес-проектов.

Бизнес-объект

В прошлом наша архитектура состояла из классов, называемых “Бизнес-объект” (у него также есть некоторые другие названия, но идея та же), это был тип класса, который содержит логику (функции) и хранит значения (он же поля).

Например, предположим, что у нас есть система, которая управляет клиентами.

public class Customer {
    private String age;
    private String name;
    private String prefix;
    // setter and getters goes here...

    public void showMe() { // some logic
        System.out.println("My name is "+name);
    }
}

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

Анемичный Объект он же Модель

Это класс, который хранит значения, в котором не должно быть логики.

public class Customer {
    private String age;
    private String name;
    private String prefix;
    // setter and getters goes here...

}

Это наш класс в базе данных

10 Джон Доктор философии
20 Анна Д-р.
30 Пол Младший

И это наш класс через сервис rest

{"age":10,"name":"John","prefix":"Phd"}

В этом может быть логика, но это не рекомендуется.

Класс обслуживания

В отличие от класса Model, в классе service отсутствуют поля, в то время как он содержит логику (метод/функции).

public class CustomerService {    
    public void showMe() {
        System.out.println("My name is "+name);
    }
}

Почему мы разделили класс?.

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

Например, предположим, что мы хотим добавить методы, которые подключаются к базе данных

public class CustomerMySql {   // usually it is called CustomerRepo etc.
    public List listAll() {
        // our code
    }
}

Что это?. Класс обслуживания. На самом деле, у нас могло бы быть столько классов обслуживания, сколько мы захотим.

Таким образом, мы также разделяем классы услуг по категориям, обычно:

  • Хранилище, DAO, Классы DAL (которые подключаются к базе данных)
  • Классы веб-сервисов.
  • Логические классы (такие как проверки, фабрика и тому подобное)
  • Другие.

И опять же, почему? Потому что код легко отлаживать и поддерживать. Допустим, у нас возникла проблема, наша система не может вставить клиента в базу данных. Итак, мы находим пространство имен (MySQL), затем находим класс, начинающийся с Customer, и мы нашли метод.

Вопрос: А как насчет сеттера и геттера?.

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

Это логика:

public class Customer {
    // ....
    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

Мы могли бы использовать Ломбок (настоятельно рекомендуется), чтобы СКРЫТЬ его но это все равно логика .

@Getter @Setter // lombok
public class Customer {
    private String age;
    private String name;
    private String prefix;
    // we don't need setter and getter.
}

Ломбок работает во время компиляции, поэтому добавлять код до его компиляции – то же самое (но код добавляется в любом случае).

Вопрос: Но ООП

Но ООП требует инкапсуляции.

ООП – это не закон, это руководство.

Вопрос: В чем проблема с сеттером и геттером?

Ясность кода.

Именно так мы используем модель с сеттером и геттером.

Customer cus=new Customer();
cus.setName("John");
System.out.println("The age is "+cus.getAge());

И это версия с открытыми полями.

Customer cus=new Customer();
cus.name="John";
System.out.println("The age is "+cus.age);

Вопрос: Мы не смогли добавить логику с общедоступными полями, не так ли?

Давайте скажем следующий код

    public void setName(String name) {
        this.name = name;
        this.prefix="Junior";
    }

Поэтому, если мы изменим имя, мы также изменим префикс. Проблема добавления логики в сеттер и геттер не очевидна.

Например:

Customer cus=new Customer();
cus.setPrefix("Dr.");
cus.setName("John");

// it will return Junior John instead of Dr. John. 

Добавление логики к сеттеру и геттеру обычно является злом.

Кроме того, мы могли бы написать логику в классе service, где ее легко отлаживать и тестировать.

Вопрос: Мы должны инкапсулировать ценности.

Да, но это не решается сеттером и геттером!.

Например, предположим, что наша модель содержит новое поле (это объект).

public class Customer {
    private String age;
    private String name;
    private String prefix;
    private Category category;
    // setter and getters
}
public class Category {
    private String nameCategory;
    // setter and getters
}

Например, предположим, что мы хотим изменить имя внутри категории:

Customer cus=new Customer();
cus.setName("John");
cus.getCategory().setNameCategory(""); // Using get to set a value @_@.

Таким образом, в нашем геттере не только отсутствует инкапсуляция (мы изменяем поле с помощью get), но и оно не является чистым.

Вопрос: Тогда, как мы могли бы инкапсулировать ценности?.

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

Мы также могли бы инкапсулировать значение, создав клон, но мы этого не делаем по очевидным причинам.

Кроме того, если мы читаем значение, которое должно быть неизменяемым, то почему мы его изменяем?. И именно здесь мы применяем SRP (Принцип простой ответственности), мы выполняем одну задачу одновременно: или мы изменяем значение, или мы считываем значение, а не то и другое.

Мы не могли бы провести модульный тест без сеттера и геттера.

Я часто это слышу

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

Мы не могли бы использовать интерфейс без сеттера и геттера.

Интерфейс полезен, потому что мы можем повторно использовать код.

Некоторые java-кодеры создают один класс, и это ТАК НЕПРАВИЛЬНО но я говорю не об этом.

И о ТВЕРДОМ)

ТВЕРДЫЙ – это ориентир, а не правило.

Но что касается интерфейса, давайте предположим, что у нас есть следующие модели:

  • Клиент (возраст, имя, префикс)
  • Сотрудник (возраст, имя, компания)

Так что имело бы смысл создать интерфейс, если не наследование. (советы: не совсем).

  • Лицо (возраст, имя)

Таким образом, наши классы реализованы как

public class Customer implements Person {
   // implementation
}
public class Employee implements Person {
   // implementation
}

public interface Person {
    String getName();
    void setName(String name);
    String getAge();
    void setAge(String age);
}

Однако использование интерфейса добавляет ЗАВИСИМОСТЬ.

Теперь давайте предположим, что мы не хотим удерживать возраст Клиенты . Если мы изменим интерфейс, то мы также изменим класс Сотрудник , следовательно, мы обнаружили проблему, потому что добавили зависимость.

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

Кроме того, трудно отлаживать код с интерфейсом.

Допустим, этот код терпит неудачу:

   SomeInterface object;
   // it fails somewhere here.

Вопрос: каков класс объекта?

Вопрос: каков класс объекта?

Не каждый объект похож. Например, визуальный объект, кнопка:

В случае визуального объекта мы используем не пару классов Модель + Сервис, а класс бизнес-объекта (класс с полями и функциями). Почему?. Потому что они подходят лучше, чем анемичная модель + класс обслуживания.

public class MyButton {
    private String Title;
    private int width;
    private int height;
    private int top;
    private int left;
    // setter and getter also functions
}

Мы также могли бы добавить логику в сеттер и геттер.

public class MyButton {
    //....
    public int getXRight() {
        return left+width; // we can use a getter with logic without a field.
    }
    public void setWidth(int width) {
        if(width<100) {
            width=100;
        }        
        this.width = width;
    }
}

Также

Иногда мы хотим стандартизировать код, т.Е. мы не хотим видеть один стиль для одного класса и другой стиль для другого класса.

Например, это правильно (в зависимости от контекста:

class Model1 {
    public int field1;
    public int field2;
}
class Model2 {
    public int field3;
    public int field4;
}

И это тоже правильно

class Model1 {
    private int field1;
    private int field2;
    // setter and getter goes here.
}
class Model2 {
    private int field3;
    private int field4;
    // setter and getter goes here.
}

Но это не так.

class Model1 { // with setter and getters
    private int field1; 
    private int field2;
    // setter and getter goes here.
}
class Model2 { // with public fields
    public int field3;
    public int field4;
}

Также (подробнее)

Некоторые библиотеки требуют использования сеттера и геттера. JSF раньше полагался на сеттер и геттер (но больше нет, мы могли использовать общедоступные поля).

Таким образом, не существует универсального решения для всех.

Подробнее о Java.

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

Последний мир.

но можем ли мы использовать класс модели с открытыми полями?. Да. C работает таким образом (C не является ООП) и некоторыми другими языками.

struct account {
   int age;
   char *name;
   char *prefix;
};

Обычно мы используем сеттер и геттер, потому что они генерируются автоматически (с помощью рефакторизации или ломбока), но затем мы используем его автоматически, компилятор JIT в любом случае заканчивает его удаление.

JIT автоматически удаляет большинство сеттеров и геттеров, которые были сгенерированы, гм, автоматически, так зачем мы добавляем?

Люди забывают, что (мы) разработчики (все еще) люди.

Например, и я повторюсь

object.getField().getOtherField().getOhNoesAnotherField().setFinalField("Some Name"); 

Неясно, в то время как (используя общедоступные поля)

object.field.otherField.ohNoesAnotherfield.finalField="Some Name"; 

Это не только коротко для написания, но и для понимания.

В качестве примечания используйте код, подобный этому:

object.getField().getOtherField().someMethod(arg,moreargs); // is cringe

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

object.Field.OtherField.OhNoesAnotherField.FinalField="Some Name"; 

В Java этого нет, и это позор.

Пример

Допустим, мы хотим показать клиенту, но нам нужен новый столбец (идентификатор), он должен быть сгенерирован автоматически, и мы не смогли сгенерировать на уровне представления/шаблона.

1 10 Джон Доктор философии
2 20 Анна Д-р.
3 30 Пол Младший

Нам не нужно отравлять наш класс моделей новым сеттером и геттером.

public class CustomerUI extends Customer {
    private int id;
    public int getId() {
        id=id+1;
        return id;
    }
}

Таким образом, этот класс работает специально для решения визуальной проблемы. Мы могли бы удалить установщик и получатель класса Customer, сохранив при этом некоторую логику

Оригинал: “https://dev.to/jorgecc/more-about-setter-and-getter-and-oop-4cpn”