월루를 꿈꾸는 대학생
[Java] 동작 파라미터화 본문
소비자의 요구사항은 항상 바뀐다 ➡️ 기능 추가는 쉽고 유지보수가 간편한 코드가 필요
동작 파라미터화
- 어떻게 실행할 것인지 결정하지 않은 코드 블록
- 나중에 프로그램에서 호출 즉 실행이 뒤로 미뤄짐
2.1 변화하는 요구사항에 대응하기
- 예제 : ==기존의 농장 재고목록에서 녹색 사과만 필터링 하는 기능 추가==
2.1.1 첫번째 시도 : 녹색 사과 필터링
public static List<Apple> filterGreenApples(List<Apple> inventory) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (apple.getColor() == Color.GREEN) { // 녹색 사과만 선택
result.add(apple);
}
}
return result;
}
녹색 사과만 필터링 하는 코드를 작성했는데 만약 추후에 녹색이 아니라 빨간색 사과를 필터링하고 싶으면? 혹은 다른 색상들을 구별하고 싶으면 어떻게 할까?
비슷한 코드가 반복 존재한다면 그 코드를 추상화하자!!
2.1.2 두번째 시도 : 색을 파라미터화
public static List<Apple> filterApplesByColor(List<Apple> inventory, Color color) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (apple.getColor() == color) {
result.add(apple);
}
}
return result;
}
// 호출할 함수들
List<Apple> greenApples = filterApplesByColor(inventroy, Green);
List<Apple> redApples = filterApplesByColor(inventroy, Red);
필터링 하고자 하는 색을 인수로 넣어서 필터링 ➡️ 요구사항에 대응 완료
다만 색 이외에 농부가 무게도 추가적으로 알고 싶다고 한다면 ??
public static List<Apple> filterApplesByWeight(List<Apple> inventory, int weight) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (apple.getWeight() > weight) {
result.add(apple);
}
}
return result;
}
무게또한 파라미터로 추가해서 필터링하도록
색상만 필터링하는 코드와 무게만 필터링 하는 코드는 매우 중복되어 있다.
DRY (같은 것을 반복하지 말것) 원칙 위반
2.1.3 세번째 시도 : 가능한 모든 속성으로 필터링
public static List<Apple> filterApplesByWeight(List<Apple> inventory, int weight, Color color, boolean flag) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if ((flag && apple.getColor().equals(color)) || (!flag && apple.getWeight() > weight)) {
// flag로 색인지 무게인지 필터링할 거 정하고 필터링한다
result.add(apple);
}
}
return result;
}
형편없는 코드
true와 false가 뭘 의미하는지 파악하기 힘들고 유연한 대응도 불가
2.2 동작 파라미터화
사과의 어떤 속성에 기초해서 참/거짓을 반환하는 함수 프리디케이트
선택 조건을 결정하는 인터페이스
public interface ApplePredicate{
boolean test (Apple apple);
}
다양한 선택 조건에 따라 여러 버전의 ApplePredicate정의 가능
public class AppleHeavyWeightPredicate implements ApplePredicate{
public boolean test(Apple apple){
return apple.getWeight()>150;
}
}
public class AppleGreenColorPredicate implements ApplePredicate{
public boolean test(Apple apple){
return GREEN.equals(apple.getColor());
}
}
![[Pasted image 20230710002357.png]]
전략 디자인패턴
- 조건에 따라 filter메서드가 다르게 동작
- 즉 전략에 따라 다르게 동작
- 각 알고리즘 (전략)을 캡슐화하는 알고리즘 패밀리를 정의하고 런타임에 알고리즘을 선택하는 기법
filterApples에서 ApplePredicate객체를 받아서 애플의 조건을 검사하도록 메서드르 고쳐야한다
동작 파라미터화 : 메서드가 다양한 동작 (전략=함수 알고리즘)을 받아서 내부적으로 다양한 동작을 수행가능
2.2.1 네번째 시도
public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p){
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(p.test(apple)){ // predicate로 사과 검사 조건을 캡슐화
result.add(apple);
}
}
returnm result;
}
더욱 유연해진 코드
AppliePredicate를 상속하는 다양한 요구사항에 맞는 전략들을 구성하면 보다 편리하게 사용 가능
static class AppleRedAndHeavyPredicate implements ApplePredicate {
@Override
public boolean test(Apple apple) {
return apple.getColor() == Color.RED && apple.getWeight() > 150;
}
}
![[Pasted image 20230710003152.png]]
한 개의 파라미터 , 다양한 동작
동작파리미터 : 컬렉션 탐색 로직과 각 항목에 동작 분리가 강점
한 메서드가 다른 동작 수행할 수 있도록 재활용 가능
![[Pasted image 20230710003441.png]]
2.3 복잡한 과정 간소화
public class FilteringApples {
public static void main(String... args) {
List<Apple> inventory = Arrays.asList(
new Apple(80, Color.GREEN),
new Apple(155, Color.GREEN),
new Apple(120, Color.RED));
List<Apple> greenApples = filterApplesByColor(inventory, new AppleGreenColorPredicate());
List<Apple> heavyApples = filter(inventory, new AppleHeavyWeightPredicate());
}
public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p ){
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(p.test(apple)){ // predicate로 사과 검사 조건을 캡슐화
result.add(apple);
}
}
returnm result;
}
}
2.3.1 익명 클래스
익명 클래스
- 지역 클래스와 비슷
- 이름이 없는 클래스
- 선언과 동시에 인스턴스화 가능 : 즉석에서 필요한 구현 만들기 가능
2.3.2 다섯번째 시도 : 익명 클래스 사용
List<Apple> redApples = filterApples(inventory, new ApplePredicate(){
return RED.equlas(apple.getColor());
})
익명 클래스는 여전히 많은 공간을 차지한다
2.3.3 여섯번째 시도 : 람다 표현식 사용
람다 사용한 코드
List<Apple> result = filterApples(inventory, (Apple apple)-> RED.equals(apple.getColor()));
![[Pasted image 20230710004600.png]]
2.3.4 일곱번째 시도 : 리스트 형식으로 추상화
public interface Predicate<T>{
boolean test(T t)
}
public static <T> List<T> filter(List<T> list, Predicate<T> p){
List<T> result = new ArrayList<>();
for(T e: list){
if(p.test(e)){
reuslt.add(e)
}
}
reutnr result;
}
List<Apple> redApples = filter(inventroy, (Apple apple) -> RED.equals(apple.getColor()));
List<Intger> evenNumbers = filter(numbers, (Integer i )-> i%2 ==0)''
동작 파라미터화 패턴은 동작을 한조각의 코드로 캡슐화 한 다음에 메서드로 전달해서 머서드의 동작을 파라미터화한다 (사과의 다양한 프리디케이트)
'Programing > Java' 카테고리의 다른 글
[Java] 자바 무슨 일이 일어나고 있는가? (0) | 2023.08.05 |
---|---|
JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가 (0) | 2022.09.13 |
CH10 날짜와 시간 & 형식화 (0) | 2021.05.16 |
ch9 java api (0) | 2021.05.09 |
ch 8 알고리즘 (0) | 2021.04.18 |