Ch06.08 Introduce Parameter Object 매개변수 객체 만들기
//[Before]
public class Station {
...
public List<Temperature> readingsOutsideRange(int min, int max) {
return readings.stream()
.filter(t -> t.getTemperature() < min || t.getTemperature() > max)
.toList();
}
}
//[After-Step01]
public class Station {
...
public List<Temperature> readingsOutsideRange(NumberRange range) {
return readings.stream()
.filter(t->t.getTemperature() < range.getMin() || t.getTemperature() > range.getMax())
.toList();
}
//[After-Step02]
public class Station {
...
public List<Temperature> readingsOutsideRange(NumberRange range) {
return readings.stream()
.filter(t->!range.contains(t.getTemperature()))
.toList();
}
}
ch06.11 split phase 단계 쪼개기
//[Before]
public class ReadOrder {
public static void main(String[] args) {
try {
if (args.length == 0) throw new RuntimeException("파일명을 입력하세요.");
String filename = args[args.length - 1];
File input = new ClassPathResource(filename).getFile();
System.out.println(input.getAbsolutePath());
ObjectMapper mapper = new ObjectMapper();
Order[] orders = mapper.readValue(input, Order[].class);
if (Stream.of(args).anyMatch(arg -> "-r".equals(arg)))
System.out.println(Stream.of(orders)
.filter(o -> "ready".equals(o.getStatus()))
.count());
else
System.out.println(orders.length);
} catch (Exception e) {
System.err.println(e);
}
}
}
//[After- 방법1]
public class ReadOrder26 {
public static long run(String[] args) throws IOException {
return countOrders(new CommandLine(args));
}
private static long countOrders(CommandLine commandLine) throws IOException {
File input = new ClassPathResource(commandLine.filename()).getFile();
ObjectMapper mapper = new ObjectMapper();
Order[] orders = mapper.readValue(input, Order[].class);
if (commandLine.onlyCountReady())
return Stream.of(orders)
.filter(Order::isReady) //캡슐화 : 메서드 이동
.count();
else
return orders.length;
}
private static class CommandLine {
String[] args;
public CommandLine(String[] args) {
if (args.length == 0) throw new RuntimeException("파일명을 입력하세요.");
this.args = args;
}
String filename() {
return args[args.length - 1];
}
boolean onlyCountReady() {
return Stream.of(args).anyMatch(arg -> "-r".equals(arg));
}
}
}
//[After-방법2]
// Strategy & Factory 적용
public class ReadOrder31 {
public static long run(String[] args) throws IOException {
return countOrders(new CommandLine(args));
}
private static long countOrders(CommandLine commandLine) throws IOException {
// 팩토리 클랫 생성
CountOrders countOrders = CountOrderFactory.createCountOrders(commandLine.onlyCountReady());
return countOrders.count(getOrders(commandLine));
}
private static Order[] getOrders(CommandLine commandLine) throws IOException {
File input = new ClassPathResource(commandLine.filename()).getFile();
ObjectMapper mapper = new ObjectMapper();
Order[] orders = mapper.readValue(input, Order[].class);
return orders;
}
private static class CommandLine {
String[] args;
public CommandLine(String[] args) {
if (args.length == 0) throw new RuntimeException("파일명을 입력하세요.");
this.args = args;
}
String filename() {
return args[args.length - 1];
}
public boolean onlyCountReady() {
return Stream.of(args).anyMatch(arg -> "-r".equals(arg));
}
}
}
public interface CountOrders {
long count(Order[] orders);
}
public class CountOrdersAll implements CountOrders {
@Override
public long count(Order[] orders) {
return orders.length;
}
}
public class CountOrdersOnlyReady implements CountOrders {
@Override
public long count(Order[] orders) {
return Arrays.stream(orders)
.filter(Order::isReady)
.count();
}
}
public class CountOrderFactory {
public static CountOrders createCountOrders(Boolean onlyCountReady) {
if (onlyCountReady)
return new CountOrdersOnlyReady();
else
return new CountOrdersAll();
}
}
Ch07.03 Replace Primitive with Object 기본형을 객체로 바꾸기
public class Order {
private final Long id;
private final String priority;
public Order(Long id, String priority) {
this.id = id;
this.priority = priority;
}
public Long getId() {
return id;
}
public String getPriority() {
return priority;
}
}
//[Before]
public class Orders {
private final Order[] orders;
public Orders(Order[] orders) {
this.orders = orders;
}
public Order[] getOrders() {
return orders;
}
public long highPriorityCount() {
return Arrays.stream(orders)
.filter(o -> o.getPriority().equals("high") || o.getPriority().equals("rush"))
.count();
}
public long lowerPriorityCount() {
return Arrays.stream(orders)
.filter(o -> o.getPriority().equals("low") || o.getPriority().equals("medium"))
.count();
}
public long lowestPriorityCount() {
return Arrays.stream(orders)
.filter(o -> o.getPriority().equals("low"))
.count();
}
public Order getOrder(int index) {
return orders[index];
}
}
class OrdersTest {
@Test
void testHighPriorityCount() {
Order[] orders = {
new Order(1L, "high"),
new Order(2L, "low"),
new Order(3L, "rush"),
new Order(4L, "medium")
};
Orders ordersObj = new Orders(orders);
assertEquals(2, ordersObj.highPriorityCount());
}
}
//[After-방법1]
// 배열 index의 순번을 우선순위 값으로 응용
public class Priority {
private final String value;
public Priority(String value) {
if (!legalValues().contains(value)){
throw new IllegalArgumentException("Invalid Priority Value");
}
this.value = value;
}
public static List<String> legalValues(){
return List.of("low", "normal", "high", "rush");
}
public int index(){
return legalValues().indexOf(value);
}
public boolean higherThan(Priority other) {
return this.index() > other.index();
}
public boolean lowerThan(Priority other) {
return this.index() < other.index();
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Priority priority = (Priority)o;
return Objects.equals(value, priority.value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
@Override
public String toString() {
return value;
}
}
//[After-방법2]
// Enum을 이용
public enum Priority {
LOW,
MEDIUM,
HIGH,
RUSH
}
public class Orders {
private final Order[] orders;
public Orders(Order[] orders) {
this.orders = orders;
}
public Order[] getOrders() {
return orders;
}
public long highPriorityCount() {
return Arrays.stream(orders)
.filter(o -> o.getPriority() == Priority.HIGH || o.getPriority() == Priority.RUSH)
.count();
}
public long lowerPriorityCount() {
return Arrays.stream(orders)
.filter(o -> o.getPriority() == Priority.MEDIUM || o.getPriority() == Priority.LOW)
.count();
}
public long lowestPriorityCount() {
return Arrays.stream(orders)
.filter(o -> o.getPriority() == Priority.LOW)
.count();
}
public Order getOrder(int index) {
return orders[index];
}
}
//[After-방법3]
// Enum에 필드값과 메서드를 이용
public enum Priority {
LOW(1),
MEDIUM(2),
HIGH(3),
RUSH(4);
Priority(int priorityLevel) {
this.priorityLevel = priorityLevel;
}
private final int priorityLevel;
public boolean isHigherThen(Priority other) {
return this.priorityLevel > other.priorityLevel;
}
public boolean isLowerThen(Priority other) {
return this.priorityLevel < other.priorityLevel;
}
public boolean isLowest() {
return this.priorityLevel == LOW.priorityLevel;
}
}
public class Orders {
private final Order[] orders;
public Orders(Order[] orders) {
this.orders = orders;
}
public Order[] getOrders() {
return orders;
}
public long highPriorityCount(Priority priority) {
return Arrays.stream(orders)
.filter(o -> o.getPriority().isHigherThen(priority))
.count();
}
public long lowerPriorityCount(Priority priority) {
return Arrays.stream(orders)
.filter(o -> o.getPriority().isLowerThen(priority))
.count();
}
public long lowestPriorityCount( ) {
return Arrays.stream(orders)
.filter(o -> o.getPriority().isLowest())
.count();
}
public long equalPriorityCount(Priority priority) {
return Arrays.stream(orders)
.filter(o -> o.getPriority().equals(priority))
.count();
}
public Order getOrder(int index) {
return orders[index];
}
}
'프로그래밍 > 리팩터링' 카테고리의 다른 글
리팩터링 2nd 10.3 중첩 조건문을 보호 구문으로 바꾸기 (0) | 2025.04.09 |
---|---|
리팩터링 2nd 8.7 Split Loop (0) | 2025.04.07 |
리팩터링 2nd Chapter 01 실습 (0) | 2025.03.25 |
리팩터링은 언제 해야 하나? (0) | 2025.02.17 |
IntelliJ가 지원하는 자동 리팩터링 목록 (1) | 2025.02.10 |