CleanCode TIL (2022.02.10)
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 원칙 지키기
Author And Source
이 문제에 관하여(CleanCode TIL (2022.02.10)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@henry/CleanCode-TIL-2022.02.10
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
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)
}
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 interface StockExchange {
Money currentPrice(String symbol);
}
public Portfolio {
private StockExchange exchange;
public Portfolio(StockExchange exchange) {
this.exchange = exchange;
}
// ... }
}
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());
}
}
- 구현에 얽매이지 말고 추상화부터 하는 습관을 길러야한다
🔎 질문
📝 소감 3줄 요약
- 클래스를 작게 분리하여 변경하기 쉽도록 한다
- 구체적인 구현보다는 추상화를 통해 변경으로부터 격리한다
- SRP, OCP, DIP 원칙 지키기
Author And Source
이 문제에 관하여(CleanCode TIL (2022.02.10)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@henry/CleanCode-TIL-2022.02.10
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
- 클래스를 작게 분리하여 변경하기 쉽도록 한다
- 구체적인 구현보다는 추상화를 통해 변경으로부터 격리한다
- SRP, OCP, DIP 원칙 지키기
Author And Source
이 문제에 관하여(CleanCode TIL (2022.02.10)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@henry/CleanCode-TIL-2022.02.10저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)