Замена вложенных условных операторов граничным оператором
Проблема
У вас есть группа вложенных условных операторов, среди которых сложно выделить нормальный ход выполнения кода.
Решение
Выделите все проверки специальных или граничных случаев выполнения в отдельные условия и поместите их перед основными проверками. В идеале, вы должны получить «плоский» список условных операторов, идущих один за другим.
public double getPayAmount() {
double result;
if (isDead){
result = deadAmount();
}
else {
if (isSeparated){
result = separatedAmount();
}
else {
if (isRetired){
result = retiredAmount();
}
else{
result = normalPayAmount();
}
}
}
return result;
}
public double getPayAmount() {
if (isDead){
return deadAmount();
}
if (isSeparated){
return separatedAmount();
}
if (isRetired){
return retiredAmount();
}
return normalPayAmount();
}
public double GetPayAmount()
{
double result;
if (isDead)
{
result = DeadAmount();
}
else
{
if (isSeparated)
{
result = SeparatedAmount();
}
else
{
if (isRetired)
{
result = RetiredAmount();
}
else
{
result = NormalPayAmount();
}
}
}
return result;
}
public double GetPayAmount()
{
if (isDead)
{
return DeadAmount();
}
if (isSeparated)
{
return SeparatedAmount();
}
if (isRetired)
{
return RetiredAmount();
}
return NormalPayAmount();
}
function getPayAmount() {
if ($this->isDead) {
$result = $this->deadAmount();
} else {
if ($this->isSeparated) {
$result = $this->separatedAmount();
} else {
if ($this->isRetired) {
$result = $this->retiredAmount();
} else {
$result = $this->normalPayAmount();
}
}
}
return $result;
}
function getPayAmount() {
if ($this->isDead) {
return $this->deadAmount();
}
if ($this->isSeparated) {
return $this->separatedAmount();
}
if ($this->isRetired) {
return $this->retiredAmount();
}
return $this->normalPayAmount();
}
def getPayAmount(self):
if self.isDead:
result = deadAmount()
else:
if self.isSeparated:
result = separatedAmount()
else:
if self.isRetired:
result = retiredAmount()
else:
result = normalPayAmount()
return result
def getPayAmount(self):
if self.isDead:
return deadAmount()
if self.isSeparated:
return separatedAmount()
if self.isRetired:
return retiredAmount()
return normalPayAmount()
getPayAmount(): number {
let result: number;
if (isDead){
result = deadAmount();
}
else {
if (isSeparated){
result = separatedAmount();
}
else {
if (isRetired){
result = retiredAmount();
}
else{
result = normalPayAmount();
}
}
}
return result;
}
getPayAmount(): number {
if (isDead){
return deadAmount();
}
if (isSeparated){
return separatedAmount();
}
if (isRetired){
return retiredAmount();
}
return normalPayAmount();
}
Причины рефакторинга
«Условный оператор из ада» довольно просто отличить. Отступы каждого из уровней вложенности формируют в нем отчётливую стрелку, указывающую вправо:
if () { if () { do { if () { if () { if () { ... } } ... } ... } while (); ... } else { ... } }
Разобраться в том, что и как делает такой оператор довольно сложно, так как «нормальный» ход выполнения в нем не очевиден. Такие операторы появляются эволюционным путём, когда каждое из условий добавляется в разные промежутки времени без мыслей об оптимизации остальных условий.
Чтобы упростить такой оператор, нужно выделить все особые случаи в отдельные условные операторы, которые бы при наступлении граничных условий, сразу заканчивали выполнение и возвращали нужное значение. По сути, ваша цель — сделать такой оператор плоским.
Порядок рефакторинга
Постарайтесь избавиться от «побочных эффектов» в условиях операторов. Разделение запроса и модификатора может в этом помочь. Такое решение понадобится для дальнейших перестановок условий.
-
Выделите граничные условия, которые приводят к вызову исключения или немедленному возвращению значения из метода. Переместите эти условия в начало метода.
-
После того как с переносами покончено, и все тесты стали проходить, проверьте, можно ли использовать объединение условных операторов для граничных условных операторов, ведущих к одинаковым исключениям или возвращаемым значениям.