предисловие
По сравнению с процедурным программированием, объектно-ориентированное программирование имеет относительно мало условных выражений, потому что многие условные поведения могут быть обработаны полиморфными механизмами; но иногда мы все же сталкиваемся с небольшими партнерами, которые их пишут. Условные выражения ничем не отличаются от процедурного программирования, например I наткнулся на этот код:
Весь код имеет три слоя, и каждый слой имеет if-else.Логика самого кода сложна для понимания.Что еще более отвратительно,так это вызывающая сторона этого метода и вызываются другие методы,что тоже самое если- еще несколько уровней вложенности; Кроме того, еще одна большая проблема с этим кодом заключается в том, что переданный объект параметра был изменен много раз во внутренних и других вызываемых методах, что делает его более трудным для понимания; это слишком сложно для понимания одноядерным процессором обычных людей. , Трудно, поддерживайте этот код, я чувствую себя опустошенным.
Иногда мы можем столкнуться с более сложной условной логикой, и нам нужно найти способ разделить ее на несколько небольших частей, чтобы разделить логику ветвления и детали операции; чтобы увидеть, как устроен код программиста, сначала посмотрите, достаточно ли его условного выражения. легко понять; сегодня мы поделимся общими методами упрощения условных выражений и попрактикуемся в собственном коде; большинство примеров в этой статье взяты из статьи "Рефакторинг и улучшение существующего дизайна кода"
Разложить условные выражения
Сложная условная логика — одно из самых распространенных мест для усложнения, кроме того, если в ветке будет много внутренней логики, мы получим очень большую функцию, а читабельность длинного метода сама по себе снизится, поэтому нам нужно поставить Только большие методы делятся на несколько методов.Для каждого метода выберите имя метода, которое легко выразить и реализовать внутреннюю логику, чтобы значительно улучшить читаемость.
Пример:
if (date.before (SUMMER_START) || date.after(SUMMER_END)) {
charge = quantity * _winterRate + _winterServiceCharge;
} else {
charge = quantity * _summerRate
}
Многим может показаться, что нет необходимости извлекать методы для такого кода, но если мы хотим понять этот код, нам все равно нужно подумать о том, что мы делаем; давайте изменим его дальше.
if (notSummer(date)) {
charge = winterCharge(quantity);
} else {
charge = summerCharge(quantity);
}
private boolean notSummer(Date date){
date.before (SUMMER_START) || date.after(SUMMER_END)
}
private double summerCharge(int quantity) {
return quantity * _summerRate;
}
private double winterCharge(int quantity) {
return quantity * _winterRate + _winterServiceCharge;
}
Очень ли понятно после этой модификации, что сам по себе хороший код не нуждается в комментариях (код говорит сам за себя), не говоря уже о каких-либо комментариях внутри метода.Я напишу небольшой комментарий, который показывает, что сам по себе код сам по себе недостаточно хорош, а читабельность кода можно улучшить на примере прямо сейчас
Комбинируйте условные выражения
При обнаружении нескольких суждений условия if в фрагменте кода, но логика внутри условий схожа, мы можем объединить условия и извлечь метод.
Пример 1:
double disabilityAmount () {
if(_seniortiy <2 )
return 0;
if(_monthsDisabled > 12)
return 0;
if(_isPartTime)
return 0;
// 省略...
}
Результаты, возвращаемые условиями здесь, одинаковы, тогда мы ставим условия слияния
double disabilityAmount () {
if(_seniortiy <2 || _monthsDisabled > 12 || _isPartTime) {
return 0;
}
// 省略...
}
Далее, давайте извлечем условие оценки условия оценки в метод для улучшения удобочитаемости.
double disabilityAmount () {
if(isNotEligibleForDisableility()) {
return 0;
}
// 省略...
}
boolean isNotEligibleForDisableility() {
return _seniortiy <2 || _monthsDisabled > 12 || _isPartTime;
}
Пример 2:
if(onVacation()) {
if(lengthOfService() > 10) {
return 2;
}
}
return 1;
код после объединения
if(onVacation() && lengthOfService() > 10){
return 2
}
return 1;
Затем мы можем использовать тернарный оператор, чтобы еще больше упростить измененный код:
return onVacation() && lengthOfService() > 10 ? 2 : 1;
На этих двух примерах мы видим, что условная логика и логика ветвления сначала разделены на разные методы, а затем мы обнаружим, что улучшение читабельности кода настолько просто и удобно, что лучший способ разделения — это ключ; Я думаю здесь должны быть аплодисменты
Объединить повторяющиеся условные фрагменты
Давайте сначала посмотрим на пример, дети в возрасте до 10 лет получают скидку 50% на цену билета
if(ageLt10(age)) {
price = price * 0.5;
doSomething();
} else {
price = price * 1;
doSomething();
}
Мы обнаружили, что разные ветки выполняют одну и ту же логику последнего кода. В это время мы можем извлечь этот код вне условного суждения. Пример здесь относительно простой. Обычно это может быть не такой простой метод, встречающийся в работе. , но много строк сложных логических условий, мы можем сначала извлечь этот код в метод, а затем поместить вызов этого метода до или после решения условия
Модифицированный код
if(ageLt10(age)) {
price = price * 0.5;
} else {
price = price * 1;
}
doSomething();
Когда мы сталкиваемся с тем же логическим кодом в try-catch, мы также можем обрабатывать его таким образом.
операторы защиты заменяют вложенные условные выражения
Как только глубоко вложенная логика оказывается глубоко вложенной логикой, это затрудняет понимание основной линии выполнения. Использоватьсяif-else
Указывает, что две ветви одинаково важны, и оба являются основным процессом линии; так же, как на следующем рисунке,
Но большую часть времени мы сталкиваемся только одним основными процессами, являются индивидуальными другими необычными обстоятельствами, в этом случаеif-else
Это не очень подходит, следует использовать оператор защиты вместо вложенного выражения.
Пример 1:
В системе компенсаций применяются специальные правила для расчета заработной платы умерших сотрудников, иностранных сотрудников и пенсионеров, такие ситуации редки и не поддаются нормальной логике;
double getPayAmount() {
double result;
if(isDead){
result = deadAmount();
} else {
if(isSeparated) {
result = separatedAmount();
} else {
if(isRetired) {
result = retiredAmount();
} else {
result = normalPayAmount();
}
}
}
return result;
}
В этом коде мы вообще не можем видеть, что такое нормальный процесс. Эти случайные ситуации скрывают нормальный процесс. Как только происходит несчастный случай, мы должны вернуться непосредственно к сопровождающему коду, чтобы увидеть бесполезную точку. просто мешает пониманию; давайте использоватьreturn
преобразовывать
double getPayAmount() {
if(isDead){
return deadAmount();
}
if(isSeparated) {
return separatedAmount():
}
if(isRetired) {
return retiredAmount();
}
return normalPayAmount();
}
Полиморфизм заменяет условные выражения
Иногда мы сталкиваемсяif-else-if
илиswitch-case
Такая структура, такой код не только неаккуратный, но и сложный для понимания при столкновении со сложной логикой. В этом случае мы можем использовать объектно-ориентированный полиморфизм для преобразования.
Пример: Если вы разрабатываете игру, вам необходимо написать метод для получения силы атаки Бартизана, Лучника и Танка, после двух часов кропотливой работы эта функция наконец завершена, код после разработки завершается следующим образом:
int attackPower(Attacker attacker) {
switch (attacker.getType()) {
case "Bartizan":
return 100;
case "Archer":
return 50;
case "Tank":
return 800;
}
throw new RuntimeException("can not support the method");
}
Проблем после самопроверки нет, и у вас в это время хорошее настроение
Когда вы отправляете код руководителю на проверку, лидер (думая об этом два часа, это слишком очевидно, чтобы идти на работу) напрямую отвечает на реализацию кода недостаточно элегантно, переписывая
1. Перечисление полиморфизма
Хотя вы очень расстроены, когда вы видите этот ответ, но вы не можете помочь, в конце концов, вы все равно должны беспокоиться здесь; ответ в порядке
Вы думали об этом некоторое время и думали, что использовать полиморфизм перечисления для его реализации недостаточно, просто делайте то, что вы говорите, поэтому вы написали следующую версию
int attackPower(Attacker attacker) {
return AttackerType.valueOf(attacker.getType()).getAttackPower();
}
enum AttackerType {
Bartizan("箭塔") {
@Override
public int getAttackPower() {
return 100;
}
},
Archer("弓箭手") {
@Override
public int getAttackPower() {
return 50;
}
},
Tank("坦克") {
@Override
public int getAttackPower() {
return 800;
}
};
private String label;
Attacker(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
public int getAttackPower() {
throw new RuntimeException("Can not support the method");
}
}
На этот раз я снова сдаю обзор лидера, и я прошел его гладко.Вы думаете, что вы достигли точки лидера.
2. класс полиморфизм
Я не ожидал, что вы будете недовольны в течение нескольких дней, и получил новый запрос. Этот метод получения силы атаки необходимо изменить. Сила атаки зависит от уровня атакующего. Учитывая, что сила атаки последняя версия является фиксированным значением. Более целесообразно использовать перечисление, и эта модификация будет рассчитывать атаку в соответствии с собственным уровнем злоумышленника. Если предполагается, что повторно использовать перечисление нецелесообразно, в то же время вы также думаете, что простая реализация была отклонена лидером в прошлый раз, если вы все еще реализуете ее на последней версии перечисления, считается, что хороших результатов не будет, в конце концов вы решите использовать полиморфизм классов для завершения
int attackPower(Attacker attacker) {
return attacker.getAttackPower();
}
interface Attacker {
default int getAttackPower() {
throw new RuntimeException("Can not support the method");
}
}
class Bartizan implements Attacker {
public int getAttackPower() {
return 100 * getLevel();
}
}
class Archer implements Attacker {
public int getAttackPower() {
return 50 * getLevel();
}
}
class Tank implements Attacker {
public int getAttackPower() {
return 800 * getLevel();
}
}
После завершения отправьте его на рассмотрение лидеру, а лидер улыбнется и пройдет код-ревью;
3. Режим стратегии
Вы думали, что все кончено, но оказалось, что план не поспевает за изменениями. После запуска игры эффект был не очень. Вы получили очередное изменение спроса. Расчет силы атаки не может быть таким грубым. Нам нужно настроить правила в фоновом режиме, чтобы разрешить некоторым игрокам участвовать в событии.Мощность атаки увеличивается в соответствии с правилами.
Вы очень злитесь, в душе думаете: "Разве вы не слышали, что для убийства программиста пистолет не нужен? Вы можете три раза изменить требования. МД хочет, чтобы я умер?"
Злиться, но не смей показывать это, кто просил тебя быть лидером, тогда давай это сделаем
Учитывая, что на этот раз к логике добавляются правила, сами правила могут быть спроектированы как простыми, так и очень сложными, если правила усложнятся на более позднем этапе, то весь класс объектов атаки будет особенно раздут, а масштабируемость не пострадает. Итак, вы больше не используете полиморфизм классов для реализации на этот раз, рассмотрите возможность использования шаблона стратегии, и код после завершения выглядит следующим образом:
//定义计算类的接口
interface AttackPowerCalculator {
boolean support(Attacker attacker);
int calculate(Attacker attacker);
}
//箭塔攻击力计算类
class BartizanAttackPowerCalculator implements AttackPowerCalculator {
@Override
public boolean support(Attacker attacker) {
return "Bartizan".equals(attacker.getType());
}
@Override
public int calculate(Attacker attacker) {
//根据规则计算攻击力
return doCalculate(getRule());
}
}
//弓箭手攻击力计算类
class ArcherAttackPowerCalculator implements AttackPowerCalculator {
@Override
public boolean support(Attacker attacker) {
return "Archer".equals(attacker.getType());
}
@Override
public int calculate(Attacker attacker) {
//根据规则计算攻击力
return doCalculate(getRule());
}
}
//坦克攻击力计算类
class TankAttackPowerCalculator implements AttackPowerCalculator {
@Override
public boolean support(Attacker attacker) {
return "Tank".equals(attacker.getType());
}
@Override
public int calculate(Attacker attacker) {
//根据规则计算攻击力
return doCalculate(getRule());
}
}
//聚合所有计算类
class AttackPowerCalculatorComposite implements AttackPowerCalculator {
List<AttackPowerCalculator> calculators = new ArrayList<>();
public AttackPowerCalculatorComposite() {
this.calculators.add(new TankAttackPowerCalculator());
this.calculators.add(new ArcherAttackPowerCalculator());
this.calculators.add(new BartizanAttackPowerCalculator());
}
@Override
public boolean support(Attacker attacker) {
return true;
}
@Override
public int calculate(Attacker attacker) {
for (AttackPowerCalculator calculator : calculators) {
if (calculator.support(attacker)) {
return calculator.calculate(attacker);
}
}
throw new RuntimeException("Can not support the method");
}
}
//入口处通过调用聚合类来完成计算
int attackPower(Attacker attacker) {
AttackPowerCalculator calculator = new AttackPowerCalculatorComposite();
return calculator.calculate(attacker);
}
Вы снова отправляете код руководителю на проверку, и руководитель им очень доволен, он похвалил вас и сказал: «Молодой человек, это неплохо, прогресс очень быстрый, ставлю вам палец вверх, вы отвечаете: Спасибо за одобрение лидера (думаю, это конечно, ведь я к нему прикасался. понятно, к чему вы)
Я думаю, что вы вполне удовлетворены завершением этой функции на этот раз, ставьте лайки, подписывайтесь и комментируйте.
Введите утверждения
Последней операцией по упрощению условных выражений является введение утверждений.Эта часть относительно проста, и сама среда Spring также предоставляет классы инструментов утверждений, такие как следующий код:
public void getProjectLimit(String project){
if(project == null){
throw new RuntimeException("project can not null");
}
doSomething();
}
Код после добавления утверждения Spring
public void getProjectLimit(String project){
Assert.notNull(project,"project can not null");
doSomething();
}
напиши в конце Спасибо за ваше терпение, чтобы прочитать это далеко. Конечно, в тексте может быть больше или меньше недостатков и ошибок.Если у вас есть предложения или мнения, вы можете их комментировать и обмениваться. Наконец, я надеюсь, что друзья смогут поставить лайк, прокомментировать и подписаться на Санлиана, потому что это все источники мотивации, которыми я могу поделиться🙏