Проработав год, я писал 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();
//登录后续
}
Это выглядит намного лучше, но если вы измените суп или нет, студенты, которые поддерживали инженерные проекты, обнаружат, что такой код в основном присутствует в проекте, а стоимость обслуживания чрезвычайно высока:
-
Метод входа в систему разделен на несколько методов.Метод входа прост, но сервис раздут.
-
После того, как сервис раздут, начните разделять сервис, а затем начните строить дополнительный уровень управления и тому подобное.
-
Крайне сложно повторно использовать, потому что метод checkUserStatus часто является приватным, и сложно сказать, подходит ли такое разделение для других бизнес-сценариев.
-
Когда код начинает казаться избыточным, он начинает писать некоторые Utils с бизнес-логикой, чтобы распространять загрязнение на Utils.
-
Из-за чрезвычайно трудных времен мультиплексирования запускается несколько похожих функций, распределенных по разным классам, и людям, которые следят за поддерживаемыми проектами, трудно отличить похожие методы.
-
Из-за плохой объединенной семантики, DTO и других объектов в затоплении, контроллере и обслуживании в сервисном слое, приводящем к разразме.
-
1, 2 фактически является бесконечным циклом, что напрямую отражается на сложности сопровождения проекта.
-
В случае нескольких источников данных и нескольких транзакций трудно определить границу транзакции, и транзакцию нельзя легко откатить.
-
Написание модульных тестов — это кошмар, студенты, которые пытаются писать модульные тесты, должны иметь глубокое понимание
Почему это так? Потому что мы пришли сюда, у нас по-прежнему процедурно-ориентированное программирование, а объектно-ориентированного мышления нет вообще. Код фактически нагроможден, а обязанности и границы не ясны, что затрудняет повторное использование, а стоимость сопровождения и изменений высока, поэтому проект станет более серьезным после сопровождения несколькими людьми. Единственный код, который выглядит как объектно-ориентированный,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.
Поняв, что такое объект, вы лучше задумаетесь о важности инкапсуляции, а затем глубоко поймете смысл шести принципов, начнете абстрагироваться от интерфейса и постепенно сформируете некоторые приемы и навыки на основе практики интерфейса, которые это шаблоны проектирования. И все это требует обдумывания при разработке, чтобы процесс написания был понятен, границы были ясны, легко ли его повторно использовать, а главное, соответствовало ли оно выражению бизнеса, а не написанию процедурного кода класс обслуживания делать что-нибудь