Pull to refresh
-3
0.2
Send message

Это виртуальные телеграммы. Принимаются на бланках на телеграфе, отпраляются по интернету, печатаются на бланках и относятся получателям.

Десять лет программировал на Delphi 7, сейчас на Java. Знаю, что очень простая и удобная система для оконных приложений и совершенно неприспособленная для веба.

Чтобы начать разрабатывать (на уровне быдлокодинга бизнес-приложений, конечно) на Delphi, достаточно было прочитать тонкую книжку на английском, идущем в комплекте. Ну может, пару книжек типа Фаронова прочитать.

Реально очень редко приходилось обращаться к гуглу чтобы спросить how to. За помощью в решении проблем - часто, да. С запросом How to, помню, обращался только, когда требовалось правильно обновлять форму, чтобы не было мерцания, и то это было в пет-проекте.

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

Марксизм - это экстремальное значение вектора, госкап посередине между диким капитализмом и марксизмом-коммунизмом. "Возврат к марксизму" здесь приведен в том смысле как ДВИЖЕНИЕ в сторону марксизма.

Я, честно говоря, не представляю, что можно гуглить в стиле "как сделать" на Delphi.

Как убедиться, что физические выключатели действительно что-то там размыкают, а не просто подают сигнал андроиду "отключить" камеру?

Слушайте, я вас понял.

ООП (и я с этим согласен) имеет массу недостатков и косяков. Spring, Дядя Боб и SOLID делают все возможное, чтобы решить проблемы ООП.

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

Конечно, в язык с ПП надо добавить возможности, которые ООП дает, в частности, Spring - бины или ссылки на модули, полиморфизм модулей, DI. Таким образом, чтобы язык процедурного программирования в конечном итоге реализовывал принципы SOLID.

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

Смоделируйте, что понадобилось добавить печать в rtf. И в одной конфигурации приложения надо вызывать один метод, а в другой - другой? А если в разные моменты разные методы? Сколько файлов пришлось перетрясти? А если один разраб будет реализовывать для rtf, а другой для html?

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

Я вам больше скажу. В современных практиках максимально отходят от наследования и заменяют их композицией. SOLID и Spring - именно про это. Бины в Spring - это, по сути, ссылки на модули в терминологии ПП, в которых определены методы для обработки объектов определенных Record-ов.

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

Так думаю:

//файл user.pas
record User 
begin
...
end;

//файл formatter.pas
interface Formatter 
begin
  format(user: User);
end;

//файл DisplayFormatter.pas
module DisplayFormatter: Formatter 
begin
  format(user: User)
  begin
    //печатаем
  end;
end;

//файл SomeClass.pas
module SomeClass
var formatter: Formatter; //Здесь система должна сама подставить
begin
  someMethod()
  var 
    user: User;
    fullName: String;
  begin
    user := ... откуда-то берем
    fullName := formatter.format(user);
    ... дальше используем fullName
  end;
end;

Вот такая система была бы просто бомба.

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

Самое главное, как вы будете определять, какую функцию передавать в другую функцию в случае, если например, для одних настроек приложения надо использовать DisplayFormatter, а для других - RTFFormatter? В Spring и вообще при применении DI фреймворк создает нужный инстанс и инжектит его в классы потребителей (в SomeClass) - в поле с интерфейсом Formatter присваивает нужный инстанс.

В Java даже специально ввели record для этого

public record ИмяRecord(Тип1 поле1, Тип2 поле2, ...) {
    // Дополнительные методы или конструкторы (если нужно)
}

Интерфейс Formatter работает только с User. Что значит "Переиспользовать для собаки" - вы угораете? Formatter работатает ТОЛЬКО с User - в этом и заключается контракт. User должен печататься ровно одним способом, как определит бизнес-аналитик (не вам решать). Собака печатается совершенно другим способом (учитывая еще развилки для WebFormatter и RTFFormatter).

Что значит "получается что Formatter зачем то требует целиком тип User со всем что у него есть, используя всего лишь firstName и lastName?"? User - это цельный законченный класс, он передается через указатель любому классу и методу, который его обрабатывает, без потрошения и изменения. Вы каждый раз распаковываете поля и передаете методу, который что-то делает с информацией из User? Зачем?

Самое главное - если потребуется поменять набор полей, добавить, например "Обращение", ("Сэр", "Леди") в User и изменить метод печати, то в моем примере, меняется только классы User, и реализации format (Интерфейсы не меняются), и SomeClass тоже не меняется. А в вашем случае придется менять ВСЕ вызовы в приложении, а их тысячи может быть. То есть, детали реализации User и печати проникают в тысячи других классов всего приложения. Не надо так.

Вообще, я не понимаю, что вы понимаете под словом "Переиспользовать"?

Да пожалуйста:

Вот ваш код:

class User {
  firstName: string
  lastName?: string
  middleName?: string
  ... // Другие поля, не нужные для getDisplayName.

  constructor(firstName: string, lastName?: string, middleName?: string) {
    this.firstName = firstName
    this.lastName = lastName
    this.middleName = middleName
  }

  // Метод.
  getDisplayName() {
    return [this.firstName, this.middleName, this.lastName]
      .filter(Boolean)
      .join(" ")
  }
  
  ... // Другие методы, не нужные для getDisplayName.
}

// Функция.
const getDisplayName = (user: {firstName: string, lastName?: string, middleName?: string} | null | undefined) => {
  if (!user) return undefined

  return [user.firstName, user.middleName, user.lastName]
    .filter(Boolean)
    .join(" ")
}

// Еще более гибко, но может быть менее удобно.
const getDisplayName = (firstName: string, lastName?: string, middleName?: string) => {
  ...
}

Вы критикуете ООП то, что в класс добавляются без конца методы, "приколочены", необходимость class extension, как костыль в шарпе и показываете, что типа функция - это круто. Отделение функциональности от данных.

Ваши придирки давным-давно разобраны Дядей Бобом. Знаете, кто это? Так узнайте, почитайте его книги. И более того, реализовано в Spring и прописано в SOLID.

Для решения вашей проблемы делается следующее.

Создается класс User

public class User {
  private String firstName;
  private String lastName;

  ... Здесь конструктор
  ... Здесь геттеры прямо либо через ломбок
}

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

public class DisplayFormatter implements Formatter {
  public String format(User user) {
    return user.getFirstName + " " + user.getLastName;
  }

  public String format2(User user) {
    return "Имя: " + user.getFirstName + ", Фамилия: " + user.getLastName;
  }
}

До кучи и при необходимости добавляем классы WebFormatter, RtfFormatter и т.д.

далее используем:

publi class SomeClass {
  private Formatter formatter = ... здесь dependency injection 
   любым доступным вам способом
    
  public SomeMethod() {
     User user = ...
     String result = formatter.format(user);
  }
}

Вот ЭТО - - гибкость (благодаря DI).

В результате набивается в дальнейшем функционал без разбухания и изменения User, что вам и хочется иметь.

А также ObjectPascal и последовавший за ним Delphi. А вдохновителем - Simula и SmalTalk.

Сериалазация и копирование:

import com.fasterxml.jackson.databind.ObjectMapper; // Для работы с JSON
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) throws Exception {
        // Создаем объект user
        List<String> friendIds = new ArrayList<>();
        friendIds.add("2");
        User user = new User("1", "Вася", "Петров", friendIds);

        // Поверхностное копирование с изменением и добавлением полей
        User updatedUser = new User(user.getId(), "Василий", user.getLastName(), user.getFriendIds());
        updatedUser.setMiddleName("Иванович"); // Добавляем опциональное поле

        // Глубокое копирование (используем сериализацию/десериализацию)
        ObjectMapper objectMapper = new ObjectMapper();
        String userJson = objectMapper.writeValueAsString(user); // Сериализация в JSON
        User clonedUser = objectMapper.readValue(userJson, User.class); // Десериализация из JSON

        // Сериализация в JSON
        String userJsonString = objectMapper.writeValueAsString(user);

        // Десериализация из JSON
        User parsedUser = objectMapper.readValue(userJsonString, User.class);

        // Вывод результатов
        System.out.println("Original User: " + user);
        System.out.println("Updated User: " + updatedUser);
        System.out.println("Cloned User: " + clonedUser);
        System.out.println("User JSON: " + userJsonString);
        System.out.println("Parsed User: " + parsedUser);
    }
}

Чем ваш код лучше этого, что ФП дает в данном примере перед ООП (Сгенерировано DeepSeek)? Функционал отделен от данных (Spring - одно большое отделение).

Вы придумываете какие-то умственные выверты, которые может "решать" ФП и не может, или с трудом - ООП, и при этом пытаетесь доказать, что язык с ООП - сложный и непонятный. Я плохо знаю ФП, и честно говоря, ни разу в своей карьере не встречал случая, когда вот прям необходимо было использовать функциональное программирование. Даже использование лямбд, когда НЕОБХОДИМО было их использовать, был всего один случай. Остальная рутина, когда постоянно используются лямбды, стримы и прочие опционалы - совершенно не являлось необходимостью, просто дань моде и признак крутизны. Да и корпоративная повестка, чо уж.

Ни одного примера на ФП, который вы привели, я не понял. Как и не понял, какие они задачи решают, в чем проблема сделать на ООП. Верю вам на слово. Разбираться, честно говоря, неохота. Когнитивная нагрузка в функциональном программировании и в этом тайпскрипте, на порядок превышает нагрузку обычного программирования на Java.

И ответственность повесили на командира экипажа.

Знаете почему Python вверху списка? Потому что на нем программируют непрограммисты - раз, а во-вторых, из-за того, что у него просто море библиотек, которые все выучить просто невозможно, меняются они часто, а язык (на самом деле) сложный, то программирование сводится к работе в паре с googl-ом. Постоянно гуглишь типа "Python pandas нормализовать колонку". Сейчас я стал постоянно использовать яндекс-нейро и deepsek, и думаю скоро "популярность" нынешних "ведущих" языков программирования внезапно станет падать.

"советские солдаты почему-то охотно сдавались в плен на первых порах " - а я о чем говорю? Зло проявляется в делах. Когда увидите первых расстрелянных, сожженных и замученных - сразу поймете, где зло, а где добро.

"По делам (плодам) их узнаете их". https://www.bible.com/ru/bible/167/MAT.7.15-20.%2525D0%2525A1%2525D0%252598%2525D0%25259D%2525D0%25259E%2525D0%252594

Information

Rating
2,889-th
Registered
Activity

Specialization

Specialist
Java
Oracle
SQL
Git
Spring Boot
Apache Maven
REST
Database