Как написать инженерный код — заново распознать объектно-ориентированный

Java

Проработав год, я писал CURD, поддерживая инженерные проекты. Недавно я изучил DDD. В сочетании с проектами с открытым исходным кодом, которые я писал ранее, я обдумал недостатки нашего метода программирования CURD. После обсуждения с друзьями я обнаружил, что мы никогда не занимались объектно-ориентированной разработкой, поэтому при написании этой статьи я надеюсь, что больше людей задумаются об объектно-ориентированной разработке, а не просто останутся на одобрении

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

нормальное развитие

Создать модель

@Data
@NoArgsConstructor
class User{
	private Integer Id;
	private String name;
	private String password;//加密过的密码
  private Integer status;//账号状态
}

class UserRepository{
  User getByName(String name);
}

Мы все знаем mvc, поэтому напишем так

class UserController{
	@RequestMapping("/login")
	public void login(String name,String password){
		userService.login(name,password);
	}
}

class UserService{
	public void login(String name,String password);
}

class UserServiceImpl implements UserService{
	public void login(String name,String password){
		//1.查出这个用户
		User user = userRepo.getByName(name);
    //2.检查状态
    if(user.getStatus()!=1){
      //登录失败
    }
    //3.检查密码
    if(!Objects.equals(md5(password),user.getPassword())){
    	//登录失败
    }
	//登录后续
	}
}

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

public void login(String name,String password){
  //1.查出这个用户
  User user = userRepo.getByName(name);
  //2.检查状态
  checkUserStatus();
  //3.检查密码
  checkPassword();
  //登录后续
}

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

  1. Метод входа в систему разделен на несколько методов.Метод входа прост, но сервис раздут.

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

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

  4. Когда код начинает казаться избыточным, он начинает писать некоторые Utils с бизнес-логикой, чтобы распространять загрязнение на Utils.

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

  6. Из-за плохой объединенной семантики, DTO и других объектов в затоплении, контроллере и обслуживании в сервисном слое, приводящем к разразме.

  7. 1, 2 фактически является бесконечным циклом, что напрямую отражается на сложности сопровождения проекта.

  8. В случае нескольких источников данных и нескольких транзакций трудно определить границу транзакции, и транзакцию нельзя легко откатить.

  9. Написание модульных тестов — это кошмар, студенты, которые пытаются писать модульные тесты, должны иметь глубокое понимание

Почему это так? Потому что мы пришли сюда, у нас по-прежнему процедурно-ориентированное программирование, а объектно-ориентированного мышления нет вообще. Код фактически нагроможден, а обязанности и границы не ясны, что затрудняет повторное использование, а стоимость сопровождения и изменений высока, поэтому проект станет более серьезным после сопровождения несколькими людьми. Единственный код, который выглядит как объектно-ориентированный,User user = userRepo.getByName(name)这一句了

Переосмыслить объектно-ориентированный

Почему вы говорите, что это предложение имеет объектно-ориентированное значение? Поскольку значение этой строки очень очевидно,кто что сделал, я думаю, что это принцип здравого смысла, в SCALA это может бытьa.do(thing)написано какa do thing,Субъект определяет ответственность, границы. Здесь пользовательское репо получает (генерирует) пользовательский объект. Хотя мы говорили об ОО, что такое инкапсуляция, наследование и полиморфизм, и шесть принципов, мы можем говорить об этом, но как только мы пишем код, это становится процедурной разработкой. Многие говорят, что шаблоны проектирования сложны для изучения и не могут быть использованы.Основная причина в том, что они не имеют представления о том, что такое объект.Как мы можем говорить об объектно-ориентированном проектировании?

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

struct User
{
   int id;
   char name[50];
   char password[50];
   int status;
} user;

Да, это структура на языке c. Конечно, вы бы не сказали, что это объект. Здесь есть недоразумение: объекты Java, о которых мы обычно говорим, на самом деле относятся к экземплярам классов в объектно-ориентированном языке Java, которые не эквивалентны объектам в объектно-ориентированных языках. Таким образом, приведенный выше объект Java не обязательно является реальным объектом OO.

могу взглянутьВикипедия говорит об объектах

что это за объект

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

@Data
@NoArgsConstructor
class User{
	private Integer Id;
	private String name;
	private String password;//加密过的密码
  private Integer status;//账号状态
  
  public boolean checkPassword(String pass){
  	return Objects.equals(md5(pass),this.password);
  }
  
  public boolean isNormal(){
  	return this.status==1
  }
  
  //这里啰嗦一下,有时候我们不太好把行为写到数据库模型类,可以单独建立一个User类,这个User类也就是DDD里面的领域对象。如果持久层使用JPA,JPA的数据模型类即是领域对象,JPA允许通过注解去把领域对象绑定到数据模型上。
}

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

public void login(String name,String password){
  //1.查出这个用户
  User user = userRepo.getByName(name);
  //2.检查状态
  if(!user.isNormal()){
  
  }
  //3.检查密码
  if(!user.checkPassword(password)){
  
  }
  //登录后续
}

Какая польза от этого

Врожденная логика — ответственность самого объекта, обязанности ясны, границы ясны, бизнес-логика унифицирована и централизована, юнит-тесты писать проще

Что еще более важно, когда наш объект User установлен, мы можем выразить связанную с пользователем логику и методы через User и можем передавать их на различных уровнях.Единый язык бизнес-выражений, что может эффективно решить проблему переполнения DTO на уровне службы. Ниже поясняется проблема DTO.

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