본문 바로가기

클린코드

[Refactoring] 20. 거대한 클래스

 

코딩으로 학습하는 리팩토링 - 인프런 | 강의

리팩토링은 소프트웨어 엔지니어가 갖춰야 할 기본적인 소양 중 하나입니다. 이 강의는 인텔리J와 자바를 사용하여 보다 실용적인 방법으로 다양한 코드의 냄새와 리팩토링 기술을 설명하고 직

www.inflearn.com

| 인프런 - 백기선님의 코딩으로 학습하는 리팩토링 강의를 수강하며 정리한 글입니다.


거대한 클래스
  • 어떤 클래스가 너무 많은 일을 하다 보면 필드도 많아지고 중복 코드도 생기기 시작한다.
  • 클래스에서 제공하는 기능 중 일부만 사용한다면 각각의 세부 기능을 별도의 클래스로 분리할 수 있다.
  • 관련 리팩토링
    • 클래스 추출하기 -> 관련 있는 필드를 한곳으로 모을 수 있다.
    • 슈퍼 클래스 추출하기, 타입 코드를 서브클래스로 교체하기 -> 상속 구조로 변경한다.
    • 클래스 내부의 중복 코드를 메서드로 추출하여 제거할 수 있다.

Refactoring 1. 슈퍼 클래스 추출하기

  • 두 개의 클래스에서 비슷한 것들이 보인다면, 상속을 적용해서 슈퍼클래스로 만들고 필드 올리기, 메서드 올리기를 사용한다.
  • 클래스 추출하기를 적용해 위임을 사용할 수도 있다.
Before
public class Department {

    private String name;

    private List<Employee> staff;

    public String getName() {
        return name;
    }

    public List<Employee> getStaff() {
        return staff;
    }

    public double totalMonthlyCost() {
        return this.staff.stream().mapToDouble(e -> e.getMonthlyCost()).sum();
    }

    public double totalAnnualCost() {
        return this.totalMonthlyCost() * 12;
    }

    public int headCount() {
        return this.staff.size();
    }
}

public class Employee {

    private Integer id;

    private String name;

    private double monthlyCost;

    public double annualCost() {
        return this.monthlyCost * 12;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public double getMonthlyCost() {
        return monthlyCost;
    }
}
After
public abstract class Party {
    protected String name;

    public Party(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public double annualCost() {
        return this.monthlyCost() * 12;
    }

    protected abstract double monthlyCost();
}

public class Department extends Party {

    private List<Employee> staff;

    public Department(String name) {
        super(name);
    }

    public List<Employee> getStaff() {
        return staff;
    }

    @Override
    public double monthlyCost() {
        return this.staff.stream().mapToDouble(e -> e.monthlyCost()).sum();
    }

    public int headCount() {
        return this.staff.size();
    }
}

public class Employee extends Party {

    private Integer id;

    private double monthlyCost;

    public Employee(String name) {
        super(name);
    }

    @Override
    protected double monthlyCost() {
        return monthlyCost;
    }

    public Integer getId() {
        return id;
    }
}

=> Department, Employee에서 공통으로 사용되는 코드를 슈퍼 클래스로 옮기고 구현