Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[recap] 리팩터링에 대하여!!! #51

Open
1winhyun opened this issue Jul 13, 2024 · 0 comments
Open

[recap] 리팩터링에 대하여!!! #51

1winhyun opened this issue Jul 13, 2024 · 0 comments
Assignees
Labels
ch9 9챕터 내용을 학습합니다 recap 학습에 관한 회고입니다.

Comments

@1winhyun
Copy link

무엇을 알게 되었나요?

리팩터링

리팩터링: 람다, 메서드 참조, 스트림 등의 기능을 이용해서 더 가독성이 좋고 유연한 코드로 만드는 방법

익명 클래스를 람다 표현식으로 리팩터링

  • 하나의 추상 메서드를 구현하는 익명 클래스는 람다 표현식으로 리팩터링 가능
  • Runnable 객체를 만드는 익명 클래스와 이에 대응하는 람다 표현식 비교
Runnable r1= new Runnable(){
    public void run(){
        System.out.println("Hello");
    }
};// 익명클래스를 사용한 코드
Runnable r2= ()-> System.out.println("Hello");//람다 표현식을 사용
  • 모든 익명클래스를 람다 표현식으로 변환 가능한 것은 아님
    1. 익명 클래스에서 사용한 this와 super는 람다 표현식에서 다른 의미를 가짐. 익명 클래스에서 this는 익명 클래스 자신을 가리키지만, 람다에서 this는 람다를 감싸는 클래스를 가리킨다.
    1. 익명 클래스는 감싸고 있는 변수를 가릴 수 있음. 하지만 람다 표현식으로는 가릴 수 없다.
    1. 익명 클래스를 람다 표현식으로 바꾸면 콘택스트 오버로딩에 따른 모호함이 생길 수 있음. 익명 클래스는 인스턴스화할 때 명시적으로 형식이 정해지지만 람다 형식은 콘택스트에 따라 달라지기 때문.

람다 표현식을 메서드 참조로 리팩터링

  • 람다 표현식 대신 메서드 참조를 이요해서 가독성을 높일 수 있음

  • 메스드 참조의 메서드명으로 코드의 의도를 명확하게 알릴 수 있기 때문.

  • 람다 표현식을 별도의 메서드로 추출한 다음 groupingBy에 인수로 전달 가능. 코드로 간결하고 의도가 명확해진다.

Map<CaloricLevel,List<Dish>> dishesByCaloricLevel=
    menu.stream().collect(groupingBy(Dish::getCaloricLevel));

public class Dish{

    {
        public CaloricLevel getCaloricLevel(){
            if(this.getCalories()<=400) return CaloricLevel.DIET;
            else if(this.getCaloris()<=700) return CaloricLevel.NORMAL;
            else return CaloricLevel.FAT;
        }
    }
}
  • 람다 표현식보다 메서드 참조가 코드의 의도를 더 명확하게 보여준다.
inventory.sort(
    (Apple a1, Apple a2)->a1.getWeight().compareTo(a2.getWeight())
);
inventroy.sort(comparing(Apple::getWeight));

명령형 데이터 처리를 스트림으로 리팩터링

  • 이론적으로 반복자를 이용한 기존의 모든 컬렉션 처리 코드를 스트림 API로 바꿔야함.
  • 스트림 API는 데이터 처리 파이프라인의 의도를 더 명확하게 보여준다.
  • 스트림은 강력한 최적화뿐 아니라 멀티코어 아키텍쳐를 활용할 수 있는 지름길 제공
List<String> dishNames=new ArrayList<>();
for(Dish dish:menu){
    if(dish.getCalories()>300){
        dishNames.add(dish.getName());
    }
}
  • 이 코드는 필터링과 추출로 엉킨 코드. 병렬로 실행시키는 것은 어려움
  • 스트림 API 사용
menu.parallelStream()
    .filter(d->d.getCalories()>300)
    .map(Dish::getName)
    .collect(toList());

람다로 객체 지향 디자인 패턴 리팩터링

전략 패턴

  • 한 유형의 알고리즘을 보유한 상태에서 런타임에 적절한 알고리즘을 선택하는 패턴.
Validator numericValidator=
    new Validator((String s)->s.matches("[a-z]+"));
boolean b1= numericValidator.validate("aaaa");
Validator lowerCaseValidator=
    new Validator((String s)-> s.mathces("\\d+"));
boolean b2=lowerCaseValidator.validate("bbbb");

템플릿 메서드

  • 알고리즘의 개요를 제시한 다음에 알고리즘의 일부를 고칠 수 있는 유연함을 제공해야하 할 때 사용하는 패턴
  • 어떤 알고리즘을 사용하고 싶은데 조금 고쳐야하는 상황일 때 적합
public void processCustomer(int id, Consumer<Custromer>makeCustomerHappy){
    Customer c=Database.getCustomerWithId(id);
    makeCustomerHappy.accept(c);
}
new OnlineBankingLambda().processCustomer(1337,(Customer c)->
    System.out.println("Hello"+c.getName()));

옵저버

  • 어떤 이벤트가 발생했을 떄 한 객체가 다른 객체 리스트에 자동으로 알림을 보내야 하는 상황에서 사용하는 패턴.
  • GUI 애플리케이션에서 자주 등장
f.registerObserver((String tweet)->{
    if(tweet!=null&&tweet.contains("money"){
        System.out.println("Breaking news in NY!"+tweet);
    })
})
  • 하지만 옵저버가 상태를 가지며, 여러 메서드를 정의하는 것과 같이 복잡하다면 람다 표현식이 더 안좋을 수도 있다.
    의무 체인
  • 작업 처리 객체의 체인을 만들 때 사용하는 패턴
  • 한 객체가 어떤 작업을 처리한 다음에 다른 객체로 결과를 전달하고, 다른 객체도 해야 할 작업을 처리한 다음에 또 다른 객체로 전달하는 식
UnaryOperator<String> headerProcessing=
    (String text)->"From Raoul,Mario and Alan:"+text;
UnaryOperator<String> spellCheckerProcessing=
    (String text)->text.replaceAll("labda","lambda");
Function<String,String>pipeline=
    headerProcessing.andThen(spellCheckerProcessing);
String result=pipeline.apply("aren 't labdas really sexy");

팩토리

  • 인스턴스화 로직을 클라이언트에 노출하지 않고 객체를 만들때 사용하는 패턴
Supplier<Product>loanSupplier=Loan::new; Loan loan=loanSupplier.get();

final Static Map<String,Supplier<Product>>map=new HashMap<>();
static{
    map.put("loan",Loan::new);
    map.put("stock",Stock::new);
    map.put("bond",Bond::new);
}

디버깅

  • 문제가 발생한 코드를 디버깅할 때는 스택 트레이스, 로깅을 확인해야함.
    스택 트레이스 확인
  • 예외 발생으로 프로그램 실행이 갑자기 중단되었다면 먼저 어디에서 멈췄고 어떻게 멈추게 되었는지 살펴봐야함.
  • 스택 프레임에서 정보를 얻을 수 있다.
  • 프로그램이 메서드를 호출할 때마다 프로그램에서의 호출 위치, 호출할 때의 인수값, 호출한 메서드의 지역 변수 등을 포함한 호출 정보가 생성되며 스택 프레임에 저장.
  • 프로그램이 멈췄다면 어떻게 멈추게 되었는지 프레임별로 보여주는 스택 트레이스를 얻을 수 있다. 즉, 문제가 발생한 지점에 이르게 된 메서드 호출 리스틀 얻을 수 있다.

어려운 내용이 있었다면 이를 어떻게 해결하였나요?

  • 구글링과 지피티 사용

어떤 자료를 참고하였나요?

No response

@1winhyun 1winhyun added recap 학습에 관한 회고입니다. ch9 9챕터 내용을 학습합니다 labels Jul 13, 2024
@1winhyun 1winhyun self-assigned this Jul 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ch9 9챕터 내용을 학습합니다 recap 학습에 관한 회고입니다.
Projects
None yet
Development

No branches or pull requests

1 participant