CleanCode TIL (2022.02.10)

21191 단어 TIL노개북TIL

DAY 20

🔖 오늘 읽은 범위 : 10. 클래스 (185~191p)


🤓 책에서 기억하고 싶은 내용

변경하기 쉬운 클래스

public class Sql {
    public Sql(String table, Column[] columns)
    public String create()
    public String insert(Object[] fields)
    public String selectAll()
    public String findByKey(String keyColumn, String keyValue)
    public String select(Column column, String pattern)
    public String select(Criteria criteria)
    public String preparedInsert()
    private String columnList(Column[] columns)
    private String valuesList(Object[] fields, final Column[] columns) private String selectWithCriteria(String criteria)
    private String placeholderList(Column[] columns)
}
  • SELECT 만 지원하다가 UPDATE 문이 필요하면 클래스를 변경해야한다 → SRP위반
abstract public class Sql {
    public Sql(String table, Column[] columns) abstract public String generate();
}
public class CreateSql extends Sql {
    public CreateSql(String table, Column[] columns) @Override public String generate()
}
public class SelectSql extends Sql {
    public SelectSql(String table, Column[] columns) @Override public String generate()
}
public class InsertSql extends Sql {
    public InsertSql(String table, Column[] columns, Object[] fields) @Override public String generate()
    private String valuesList(Object[] fields, final Column[] columns)
}
public class SelectWithCriteriaSql extends Sql {
    public SelectWithCriteriaSql(
        String table, Column[] columns, Criteria criteria) @Override public String generate()
}
public class SelectWithMatchSql extends Sql {
    public SelectWithMatchSql(
        String table, Column[] columns, Column column, String pattern) @Override public String generate()
}
public class FindByKeySql extends Sql public FindByKeySql(
    String table, Column[] columns, String keyColumn, String keyValue)
@Override public String generate()
}
public class PreparedInsertSql extends Sql {
    public PreparedInsertSql(String table, Column[] columns) @Override public String generate() {
        private String placeholderList(Column[] columns)
    }
    public class Where {
        public Where(String criteria) public String generate()
    }
    public class ColumnList {
        public ColumnList(Column[] columns) public String generate()
    }
}
  • public 인터페이스를 Sql 클래스에서 파생하는 클래스로 분리
  • valuList와 같은 private 메서드는 해당 파생 클래스로 이동
  • 공통으로 사용하는 private 메서드는 Where 과 ColumnList 라는 유틸 클래스에 포함
  • UPDATE 문을 추가할때도 새 UpdateSql 이라는 클래스만 상속받아 넣는다 → 다른코드는 망가지지않음
  • SRP 지원
  • OpenClosedPrinciple 지원: 확장에 개방적이고 수정에 폐쇄적이어야 한다

변경으로부터 격리

  • 상세한 구현에 의존하는 클라이언트 클래스는 구현이 바뀌면 위험하다 → 인터페이스와 추상 클래스를 사용해 격리

주식 Portfolio 클래스

  • 5분마다 값이 달라지는 TokyoStockExchange API 로 테스트 코드를 짜기 어렵다
  • API 직접 호출하는 대신 StockExchange 라는 인터페이스 생성 후 메서드 선언
public interface StockExchange {
    Money currentPrice(String symbol);
}
  • StockExchange 인터페이스를 구현하는 TokyoStockExchange 클래스 구현
  • Portfolio 생성자에서 StockExchange 참조자 인수로 받음
public Portfolio {
    private StockExchange exchange;
    public Portfolio(StockExchange exchange) {
        this.exchange = exchange;
    }
    // ... }
}
  • 테스트 클래스는 StockExchange 인터페이스를 구현하며 고정된 주가를 반환(100불)
  • 전체 portfolio 총계가 500불인지 확인하는 테스트 작성 가능
public class PortfolioTest {
    private FixedStockExchangeStub exchange;
    private Portfolio portfolio;
    @Before
    protected void setUp() throws Exception {
        exchange = new FixedStockExchangeStub();
        exchange.fix("MSFT", 100);
        portfolio = new Portfolio(exchange);
    }
    @Test
    public void GivenFiveMSFTTotalShouldBe500() throws Exception {
        portfolio.add(5, "MSFT");
        Assert.assertEquals(500, portfolio.value());
    }
}
  • 시스템 결합도를 낮췄기 때문에 유연성과 재사용성 높아짐
  • DIP(Dependency Inversion Principle)를 따름: 클래스가 상세한 구현이 아니라 추상화에 의존해야 한다
  • Portfolio 클래스는 TokyoStockExchange 라는 상세한 구현 클래스가 아니라 StockExchange 인터페이스에 의존하기 때문에 주가를 얻어오는 출처나 등 구체적인 사실을 숨기고 격리할 수 있음

🤔 떠오르는 생각

  • 구현에 얽매이지 말고 추상화부터 하는 습관을 길러야한다

🔎 질문

📝 소감 3줄 요약

  • 클래스를 작게 분리하여 변경하기 쉽도록 한다
  • 구체적인 구현보다는 추상화를 통해 변경으로부터 격리한다
  • SRP, OCP, DIP 원칙 지키기

좋은 웹페이지 즐겨찾기