Автор: Брат Сяофу
Блог:bugstack.cn - 原创系列专题文章
Осаждайте, делитесь, растите и позвольте себе и другим что-то получить! 😄
Введение
场地和场景的重要性
Стрельбе🏹 нужно ходить в тир, чтобы учиться, лыжам🏂 нужно ехать на снежное поле, чтобы испытать, водить🚗 нужно уметь практиковаться в дороге, а разработка программирования может не только завершить функциональный процесс продукта, но также необходимо обеспечить надежную работу системы. Например, вы можете услышать некоторые показатели системного мониторинга;QPS
,TPS
,TP99
,TP999
,可用率
,响应时长
И так далее, а суммарная оценка этих показателей и есть работоспособность системы. Но если вы вряд ли слышали такие технические термины, и не сталкивались с подобными высокопараллельными сценариями, то очень похоже на предмет 1 водительского удостоверения, но в дорогу не попасть. Нет такой технической сцены, чтобы вы могли тренироваться, чтобы вы могли постоянно испытывать темперамент системы, даже если у вас много идей, вы не можете их реализовать. Поэтому, если вы действительно хотите учиться, вы должны пойти на сцену с практическими действиями, а затем вы можете научиться делать дог-планку, попробовав это в воде.
你的视觉盲区有多大
Та же книга, та же дорога, тот же город, ты правда думаешь, что у жизни есть выбор? Иногда многие варианты — это просто украшения, и вы выбирали ровно столько раз, сколько вам дают. Дело не в том, выбираете вы или нет, а в том, что ваши когнитивные возможности определяют, что вы делаете в следующую секунду, а следующая секунда определяет следующую секунду. Так же, как леопард в трубке, 20% площади чёрное в твоём зрении, и даже невидимое ты игнорируешь, а невидимые 20% - это удача в жизни! Однако люди могут учиться, расти, изобретать себя заново, усердно работать и видеть оставшиеся 20% через повторные преобразования!
没有设计图纸你敢盖楼吗
Лучшее в разработке программирования — это дизайн. Используйте архитектурное мышление, опыт,才华灵感
, чтобы построить лучшую систему. Настоящие R&D оценят код, написанный своими руками, как работу.Вы говорите, что это работа, а в глазах таких людей это не работа, а мастерство. Как, может быть, иногда вы будете делать это для себя из-заniubility
Дизайн очень смелый, и он будет обновлен, чтобы иметь возможность запускать систему, способную выдерживать 2 миллиона посещений в секунду. Такая гордость подобна строительным кирпичикам, которые снова и снова поднимают подошвы ваших ног, постоянно улучшая ваше зрение, чтобы вы могли видеть дизайн верхнего уровня и знать конструкцию фундамента. Вы можете контролировать общую ситуацию и управлять деталями. Это накопление знаний поможет вам нарисовать план системной архитектуры.
2. Среда разработки
- JDK 1.8
- Idea + Maven
- Участвуют три проекта, которые можно получить, обратив внимание наНет публики:
bugstack虫洞栈
,Отвечать源码下载
Получить (открыть ссылку для получения, найти серийный номер 18)
проект | описывать |
---|---|
itstack-demo-design-13-00 | Проект моделирования сценария; смоделируйте интерфейс для онлайн-утверждения процесса. |
itstack-demo-design-13-01 | Используйте фрагмент кода для реализации бизнес-требований |
itstack-demo-design-13-02 | Оптимизируйте и преобразовывайте код с помощью шаблонов проектирования, создавайте контраст и учитесь |
3. Введение в модель цепочки ответственности
Барабанная дробь и гром, Глядя на картинку выше, помните ли вы, что у Стивена Чоу был фильм, где все сидели в кругу у моря, держа в руках зажженную бомбу и передавая ее друг другу.
Ядро модели цепочки ответственности заключается в решении последовательного отношения выполнения и обработки в наборе услуг.Это немного похоже на то, что если у вас нет денег, чтобы тратить, вам нужно одобрить финансовые расходы семьи.Если денег меньше чем 10 юаней, невестка одобрит это, а невестка одобрит одобрение невестки за 100 юаней. Вы можете понять и представить, что, когда вы хотите сменить работу, вас устраивают на подписание и освобождение различными руководителями.
4. Моделирование сценария
В этом случае мы моделируем сценарий процесса онлайн-утверждения бизнес-системы в течение периода продвижения 618.
Например, такие интернет-компании первой линии электронной коммерции, как Ali, JD.com, Pinduoduo и т. д., проведут некоторые оперативные мероприятия и обеспечат подготовку к расширению в период 618 года, точно так же, как красные конверты Baidu во время китайского Нового года. Однако все эти развитые системы нужно запускать одну за другой, потому что иногда бывают какие-то срочные корректировки, которые нужно запускать около 618, но для обеспечения стабильности онлайн-системы, онлайн-система будет сокращена аж на возможно, и одобрение будет соответственно усилено. Также как первичная реакция, вторичная реакция.
И этот процесс утверждения добавит ответственных лиц разных уровней в определенный момент времени, и каждый человек подобен каждому основному звену в модели цепочки ответственности. Для партнеров по НИОКР вам не нужно заботиться о конкретных деталях обработки процесса утверждения, вам нужно только знать, что этот запуск более строгий и уровень выше, но для сотрудников НИОКР они также нажимают ту же кнопку проверки и ждут для рассмотрения.
Затем мы моделируем такой сценарий бизнес-требований и используем шаблон проектирования цепочки ответственности для достижения этой функции.
1. Проект моделирования сценария
itstack-demo-design-13-00
└── src
└── main
└── java
└── org.itstack.demo.design
└── AuthService.java
- Структура кода здесь относительно проста, всего один класс службы для имитации аудита и запроса результатов аудита. Это эквивалентно вызову этого класса для аудита проекта и получения структуры аудита.Эта часть информации о результатах моделируется и записывается в реализацию кэша.
2. Краткое описание сцены
2.1 Служба имитации аудита
public class AuthService {
private static Map<String, Date> authMap = new ConcurrentHashMap<String, Date>();
public static Date queryAuthInfo(String uId, String orderId) {
return authMap.get(uId.concat(orderId));
}
public static void auth(String uId, String orderId) {
authMap.put(uId.concat(orderId), new Date());
}
}
- Здесь предусмотрено два интерфейса, один из которых предназначен для запроса результатов аудита (
queryAuthInfo
), другой обрабатывает аудит (auth
). - Эта часть предназначена для записи того, кто просматривал и просматривал один идентификатор в качестве уникального значения ключа в структуре карты памяти.
5. Реализуйте с помощью фрагмента кода
这里我们先使用最直接的方式来实现功能
В соответствии с нашим процессом утверждения требований, система обычно нуждается только в утверждении ответственного лица третьего уровня, но во время повышения 618 ответственное лицо второго уровня и ответственное лицо первого уровня должны присоединиться процесс утверждения системы онлайн вместе. Здесь мы используем очень прямой метод суждения, чтобы выполнить такое требование.
1. Инженерное сооружение
itstack-demo-design-13-01
└── src
└── main
└── java
└── org.itstack.demo.design
└── AuthController.java
- Эта часть очень проста и содержит только класс управления аудитом, так же, как некоторые партнеры начинают писать код, один класс пишет все требования.
2. Реализация кода
public class AuthController {
private SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 时间格式化
public AuthInfo doAuth(String uId, String orderId, Date authDate) throws ParseException {
// 三级审批
Date date = AuthService.queryAuthInfo("1000013", orderId);
if (null == date) return new AuthInfo("0001", "单号:", orderId, " 状态:待三级审批负责人 ", "王工");
// 二级审批
if (authDate.after(f.parse("2020-06-01 00:00:00")) && authDate.before(f.parse("2020-06-25 23:59:59"))) {
date = AuthService.queryAuthInfo("1000012", orderId);
if (null == date) return new AuthInfo("0001", "单号:", orderId, " 状态:待二级审批负责人 ", "张经理");
}
// 一级审批
if (authDate.after(f.parse("2020-06-11 00:00:00")) && authDate.before(f.parse("2020-06-20 23:59:59"))) {
date = AuthService.queryAuthInfo("1000011", orderId);
if (null == date) return new AuthInfo("0001", "单号:", orderId, " 状态:待一级审批负责人 ", "段总");
}
return new AuthInfo("0001", "单号:", orderId, " 状态:审批完成");
}
}
- Здесь оценивается сверху вниз, что утверждение осуществляется разными людьми в течение указанного диапазона времени.Точно так же, как когда 618 подключается к сети, необходимо, чтобы все три ответственных лица утвердили его, прежде чем система сможет подключиться к сети.
- Такая функция выглядит простой, но в реальном бизнесе есть много отделов, но если она реализована таким образом, ее трудно расширять, а также очень хлопотно изменять и расширять.
3. Тестовая проверка
3.1 Написание тестовых классов
@Test
public void test_AuthController() throws ParseException {
AuthController authController = new AuthController();
// 模拟三级负责人审批
logger.info("测试结果:{}", JSON.toJSONString(authController.doAuth("小傅哥", "1000998004813441", new Date())));
logger.info("测试结果:{}", "模拟三级负责人审批,王工");
AuthService.auth("1000013", "1000998004813441");
// 模拟二级负责人审批
logger.info("测试结果:{}", JSON.toJSONString(authController.doAuth("小傅哥", "1000998004813441", new Date())));
logger.info("测试结果:{}", "模拟二级负责人审批,张经理");
AuthService.auth("1000012", "1000998004813441");
// 模拟一级负责人审批
logger.info("测试结果:{}", JSON.toJSONString(authController.doAuth("小傅哥", "1000998004813441", new Date())));
logger.info("测试结果:{}", "模拟一级负责人审批,段总");
AuthService.auth("1000011", "1000998004813441");
logger.info("测试结果:{}", "审批完成");
}
- Это имитирует завершение утверждения каждого запроса.При утверждении разных узлов операция утверждения будет продолжать выполняться разными ответственными лицами.
-
authController.doAuth
, это узел процесса для просмотра утверждения,AuthService.auth
, — это метод утверждения, используемый для управления состоянием процесса узла.
3.2 Результаты испытаний
23:25:00.363 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:{"code":"0001","info":"单号:1000998004813441 状态:待三级审批负责人 王工"}
23:25:00.366 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:模拟三级负责人审批,王工
23:25:00.367 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:{"code":"0001","info":"单号:1000998004813441 状态:待二级审批负责人 张经理"}
23:25:00.367 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:模拟二级负责人审批,张经理
23:25:00.368 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:{"code":"0001","info":"单号:1000998004813441 状态:待一级审批负责人 段总"}
23:25:00.368 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:模拟一级负责人审批,段总
23:25:00.368 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:审批完成
Process finished with exit code 0
- Из результатов тестирования видно, что слои утверждаются разными сотрудниками, и после завершения утверждения этим занимается следующий человек. Просто смотреть на результат — это удовлетворять нашим требованиям, но трудно расширять и настраивать процесс, который эквивалентен написанию кода.
6. Код рефакторинга модели цепочки ответственности
接下来使用装饰器模式来进行代码优化,也算是一次很小的重构。
Модель цепочки ответственности может сделать каждый сервисный модуль более понятным, и каждый модуль может пройтиnext
способ получения. и каждыйnext
Реализуется унаследованным унифицированным абстрактным классом. В конце концов, обязанности всех классов могут быть динамически поставлены и использованы, а процесс хореографии можно сделать настраиваемым.
1. Инженерное сооружение
itstack-demo-design-13-02
└── src
└── main
└── java
└── org.itstack.demo.design
├── impl
│ ├── Level1AuthLink.java
│ ├── Level2AuthLink.java
│ └── Level3AuthLink.java
├── AuthInfo.java
└── AuthLink.java
Структура модели шаблона цепочки ответственности
- Приведенный выше рисунок является основной частью структуры цепочки ответственности в этой бизнес-модели, которая реализует единый абстрактный класс через три
AuthLink
различные правила, а затем выполнить договоренность об ответственности, чтобы имитировать ссылку. Это звено — цепочка ответственности в бизнесе. - Как правило, при использовании цепочки ответственности, если сцена относительно фиксирована, ее можно инициализировать, прописав ее в коде. Однако, если бизнес-сценарий часто меняется, его можно обработать с помощью конфигурации xml или инициализировать в библиотеке.
2. Реализация кода
2.1 Определение возвращаемых объектов в цепочке ответственности
public class AuthInfo {
private String code;
private String info = "";
public AuthInfo(String code, String ...infos) {
this.code = code;
for (String str:infos){
this.info = this.info.concat(str);
}
}
// ...get/set
}
- Этот класс является классом, который упаковывает результаты, возвращаемые в процессе цепочки ответственности, и обрабатывает возвращаемую информацию каждой цепочки ответственности.
2.2 Определение абстрактного класса ссылки
public abstract class AuthLink {
protected Logger logger = LoggerFactory.getLogger(AuthLink.class);
protected SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 时间格式化
protected String levelUserId; // 级别人员ID
protected String levelUserName; // 级别人员姓名
private AuthLink next; // 责任链
public AuthLink(String levelUserId, String levelUserName) {
this.levelUserId = levelUserId;
this.levelUserName = levelUserName;
}
public AuthLink next() {
return next;
}
public AuthLink appendNext(AuthLink next) {
this.next = next;
return this;
}
public abstract AuthInfo doAuth(String uId, String orderId, Date authDate);
}
- Эта часть представляет собой цепочку ответственности,связатьосновная часть.
AuthLink next
, дело в том, чтоnext
способ получить узел, который необходимо обработать в следующей ссылке. -
levelUserId
,levelUserName
, является общедоступной информацией в цепочке ответственности, маркирующей кадровую информацию каждого узла аудита. - Абстрактный метод определяется в абстрактном классе,
abstract AuthInfo doAuth
Это класс, который необходимо реализовать, а разные уровни аудита имеют разные службы.
2.3 Три класса реализации аудита
Level1AuthLink
public class Level1AuthLink extends AuthLink {
public Level1AuthLink(String levelUserId, String levelUserName) {
super(levelUserId, levelUserName);
}
public AuthInfo doAuth(String uId, String orderId, Date authDate) {
Date date = AuthService.queryAuthInfo(levelUserId, orderId);
if (null == date) {
return new AuthInfo("0001", "单号:", orderId, " 状态:待一级审批负责人 ", levelUserName);
}
AuthLink next = super.next();
if (null == next) {
return new AuthInfo("0000", "单号:", orderId, " 状态:一级审批完成负责人", " 时间:", f.format(date), " 审批人:", levelUserName);
}
return next.doAuth(uId, orderId, authDate);
}
}
Level2AuthLink
public class Level2AuthLink extends AuthLink {
private Date beginDate = f.parse("2020-06-11 00:00:00");
private Date endDate = f.parse("2020-06-20 23:59:59");
public Level2AuthLink(String levelUserId, String levelUserName) throws ParseException {
super(levelUserId, levelUserName);
}
public AuthInfo doAuth(String uId, String orderId, Date authDate) {
Date date = AuthService.queryAuthInfo(levelUserId, orderId);
if (null == date) {
return new AuthInfo("0001", "单号:", orderId, " 状态:待二级审批负责人 ", levelUserName);
}
AuthLink next = super.next();
if (null == next) {
return new AuthInfo("0000", "单号:", orderId, " 状态:二级审批完成负责人", " 时间:", f.format(date), " 审批人:", levelUserName);
}
if (authDate.before(beginDate) || authDate.after(endDate)) {
return new AuthInfo("0000", "单号:", orderId, " 状态:二级审批完成负责人", " 时间:", f.format(date), " 审批人:", levelUserName);
}
return next.doAuth(uId, orderId, authDate);
}
}
Level3AuthLink
public class Level3AuthLink extends AuthLink {
private Date beginDate = f.parse("2020-06-01 00:00:00");
private Date endDate = f.parse("2020-06-25 23:59:59");
public Level3AuthLink(String levelUserId, String levelUserName) throws ParseException {
super(levelUserId, levelUserName);
}
public AuthInfo doAuth(String uId, String orderId, Date authDate) {
Date date = AuthService.queryAuthInfo(levelUserId, orderId);
if (null == date) {
return new AuthInfo("0001", "单号:", orderId, " 状态:待三级审批负责人 ", levelUserName);
}
AuthLink next = super.next();
if (null == next) {
return new AuthInfo("0000", "单号:", orderId, " 状态:三级审批负责人完成", " 时间:", f.format(date), " 审批人:", levelUserName);
}
if (authDate.before(beginDate) || authDate.after(endDate)) {
return new AuthInfo("0000", "单号:", orderId, " 状态:三级审批负责人完成", " 时间:", f.format(date), " 审批人:", levelUserName);
}
return next.doAuth(uId, orderId, authDate);
}
}
- Вышеуказанные три категории;
Level1AuthLink
,Level2AuthLink
,Level3AuthLink
, который реализует простую логику обработки на разных уровнях аудита. - Например, в первом классе аудита он сначала определит, пройден ли аудит, и если он не пройден, результат будет возвращен вызывающей стороне для руководства аудитом.(Информация о времени не является пустой после простого обзора моделирования здесь, в качестве условия суждения)
- После завершения оценки получается следующий узел аудита;
super.next();
, если следующего узла нет, вернуть результат напрямую. - После этого необходимо решить, необходимо ли это в соответствии с различными временными периодами бизнеса, и проводятся проверки второго и первого уровня.
- Наконец, вернуть следующий результат аудита;
next.doAuth(uId, orderId, authDate);
, что-то вроде рекурсивного вызова.
3. Тестовая проверка
3.1 Написание тестовых классов
@Test
public void test_AuthLink() throws ParseException {
AuthLink authLink = new Level3AuthLink("1000013", "王工")
.appendNext(new Level2AuthLink("1000012", "张经理")
.appendNext(new Level1AuthLink("1000011", "段总")));
logger.info("测试结果:{}", JSON.toJSONString(authLink.doAuth("小傅哥", "1000998004813441", new Date())));
// 模拟三级负责人审批
AuthService.auth("1000013", "1000998004813441");
logger.info("测试结果:{}", "模拟三级负责人审批,王工");
logger.info("测试结果:{}", JSON.toJSONString(authLink.doAuth("小傅哥", "1000998004813441", new Date())));
// 模拟二级负责人审批
AuthService.auth("1000012", "1000998004813441");
logger.info("测试结果:{}", "模拟二级负责人审批,张经理");
logger.info("测试结果:{}", JSON.toJSONString(authLink.doAuth("小傅哥", "1000998004813441", new Date())));
// 模拟一级负责人审批
AuthService.auth("1000011", "1000998004813441");
logger.info("测试结果:{}", "模拟一级负责人审批,段总");
logger.info("测试结果:{}", JSON.toJSONString(authLink.doAuth("小傅哥", "1000998004813441", new Date())));
}
- Это включает в себя создание основной цепочки ответственности, которая будет интегрирована в контрольный уровень в реальном бизнесе;
AuthLink authLink = new Level3AuthLink("1000013", "王工") .appendNext(new Level2AuthLink("1000012", "张经理") .appendNext(new Level1AuthLink("1000011", "段总")));
Путем сборки различных узлов ответственности формируется полная цепочка бизнес-ответственности. - Далее продолжаем выполнять ссылку просмотра аудита
authLink.doAuth(...)
, и данные будут проверяться руководителями уровней 3, 2 и 1 по возвращенным результатам до тех пор, пока не будет завершена окончательная проверка.
3.2 Результаты испытаний
23:49:46.585 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:{"code":"0001","info":"单号:1000998004813441 状态:待三级审批负责人 王工"}
23:49:46.590 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:模拟三级负责人审批,王工
23:49:46.590 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:{"code":"0001","info":"单号:1000998004813441 状态:待二级审批负责人 张经理"}
23:49:46.590 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:模拟二级负责人审批,张经理
23:49:46.590 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:{"code":"0001","info":"单号:1000998004813441 状态:待一级审批负责人 段总"}
23:49:46.590 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:模拟一级负责人审批,段总
23:49:46.590 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:{"code":"0000","info":"单号:1000998004813441 状态:一级审批完成负责人 时间:2020-06-18 23:49:46 审批人:段总"}
Process finished with exit code 0
- Из приведенных выше результатов мы видим, что наша цепочка ответственности вступила в силу.Согласно структуре цепочки ответственности, мы будем утверждать ее слой за слоем до окончательного результата от конца утверждения до завершения первого уровень выводится.
- Таким образом, метод проектирования цепочки ответственности может быть легко расширен и сохранен, а оператор if также устранен.
7. Резюме
- Из приведенного выше рефакторинга кода от оператора if до разработки с использованием модели цепочки ответственности мы видим, что наша структура кода стала ясной и чистой, а также было решено использование большого количества операторов if. Дело не в том, что оператор if плохой, просто оператор if не подходит для проектирования системных процессов, но он все же очень полезен для обработки суждений и логики поведения.
- Мы говорили о комбинированном паттерне в нашем предыдущем исследовании структурных паттернов, это похоже на комбинированное дерево, и мы строим процессное дерево решений. На самом деле, эту модель также можно комбинировать и расширять с моделью цепочки ответственности, и основное внимание в этой части уделяется тому, как связатьссылка на ассоциацию, окончательное выполнение находится в выполнении цепочки отношений в середине.
- Модель цепочки ответственности очень хорошо обрабатывает единую ответственность и принцип открытости-закрытости, упрощает связывание и делает объектные отношения более понятными, а внешнему вызывающему объекту не нужно заботиться о том, как обрабатывается цепочка ответственности. выше, цепочка ответственности может быть объединена в пакет и предоставлена для внешнего использования)*. Но в дополнение к этим преимуществам его также необходимо использовать в соответствующих сценариях, чтобы избежать проблем с производительностью и хаотичных упущений при отладке и тестировании.