본문 바로가기

Programming/기초지식

[객체 지향] 캡슐화 연습

반응형

연습1

아래 코드는 id와 pwd값을 통해 계정의 유효성을 판단하는 코드이다.

public AuthResult authenticate(String id, String pwd) {
    Member member = findOne(id);
    if(member == null) return AuthResult.NO_MATCH;
    
    if(member.getVefiricationEmailStatus() != 2) {
    	return AuthResult.NO_EMAIL_VERIFIED;
    }
    
    if(passwordEncoder.isPasswordValid(member.getPassword(), pwd, member.getId())) {
    	return AuthResult.SUCCESS;
    }
    
    return AuthResult.NO_MATCH;
}

 

위 코드는 캡슐화의 규칙인 Tell, Don't Ask가 적용된다. 데이터를 가져와서 판단하지 말고, 판단해달라고 부탁한다.

해당 관점에서 코드를 살펴보면 중앙의 getVerificationEmailStatus() 메서드를 수정할 수 있다. 이 메서드는 직접 데이터 값을 가져와서 판단하고 있다. 

 

getVerificationEmailStatus() 메서드를 캡슐화한 결과는 아래와 같다.

 

public AuthResult authenticate(String id, String pwd) {
    Member member = findOne(id);
    if(member == null) return AuthResult.NO_MATCH;
    
    if(member.isEmailVerifiedd()) {
    	return AuthResult.NO_EMAIL_VERIFIED;
    }
    
    if(passwordEncoder.isPasswordValid(member.getPassword(), pwd, member.getId())) {
    	return AuthResult.SUCCESS;
    }
    
    return AuthResult.NO_MATCH;
}

public class Member {
	private int verificationEmailStatus;
    
    public boolean isEmailVerifiedd() {
    	return verificationEmailStatus == 2;
    }
}

 

연습2

아래 코드는 영화 렌털 정보를 담은 Rental 클래스와 렌털 되는 영화 정보를 담은 Movie 클래스이다.

public class Rental {
    private Movie movie;
    private int daysRented;
    
    public int getFrequentRenterPoints() {
    	if(movie.getPriceCode() == Movie.NEW_RELEASE && daysRented > 1) 
        	return 2;
        else
        	return 1;
    }
    ...
}

public class Movie {
    public static int REGULAR = 0;
    public static int NEW_RELEASE = 1;
    private int priceCode;
    
    public int getPriceCode() {
    	return priceCode;
    }
    ...
}

 

위 코드는 캡슐화의 규칙인 Tell, Don't Ask가 적용된다. 데이터를 가져와서 판단하지 말고, 판단해달라고 부탁한다.

해당 관점에서 코드를 살펴보면 중앙의 getPriceCode() 메서드를 수정할 수 있다. 이 메서드는 직접 데이터 값을 가져와서 판단하고 있다. 

 

getPriceCode() 메서드를 캡슐화한 결과는 아래와 같다.

 

public class Rental {
    private Movie movie;
    private int daysRented;
    
    public int getFrequentRenterPoints() {
    	return movie.getFrequentRenterPoints(daysRented);
    }
    ...
}

public class Movie {
    public static int REGULAR = 0;
    public static int NEW_RELEASE = 1;
    private int priceCode;
    
    public int getFrequentRenterPoints(int daysRented) {
    	if(priceCode == NEW_RELEASE && daysRented > 1)
        	return 2;
        else
        	return 1;
    }
    ...
}

 

연습3

아래 코드는 시간을 표시하는 프로퍼티를 가진 Timer 클래스와 이를 이용해 시작 시간과 종료 시간 등을 구하는 구현 코드이다.

Timer t = new Timer();
t.startTime = System.currentTimeMillis();
...
t.stopTime = System.currentTimeMillis();
long elapsedTime = t.stopTime - t.startTime;

// Timer 클래스
public class Timer {
    public long startTime;
    public long stopTime;
}

 

이 코드는 t.startTime, t.stopTime과 같이 클래스의 데이터를 직접 가져와서 사용하고 있는 전형적인 절차 지향적인 방식을 취하고 있다.

 

이를 캡슐화한 결과는 아래와 같다.

start(), stop(), elapsedTime() 메서드를 정의하여 캡슐화하였다.

 

Timer t = new Timer();
t.start();
...
t.stop();
long time = t.elapsedTime(MILLISECOND);

// Timer 클래스
public class Timer {
    private long startTime;
    private long stopTime;
    
    public void start() {
    	this.startTime = System.currentTimeMillis();
    }
    
    public void stop() {
    	this.stopTime = System.currentTimeMillis();
    }
    
    public elapsedTime(TimeUnit unit) {
    	switch(unit) {
        	case MILLISECOND:
            	return stopTime - startTime;
            ...
        }
    }
}

 

연습4

아래 코드는 findByToken() 메서드로 특정 토큰과 관련된 member를 구하고 있다. 또한 이메일 인증 관련 처리를 하는 메서드가 정의되어 있다.

public void verifyEmail(String token) {
    Member member = findByToken(token);
    if(member == null) throw new BadTokenException();
    
    if(member.getVerificationEmailStatus() == 2) {
        throw new AlreadyVerifiedException();
    }else{
        member.setVerificationEmailStatus(2);
    }
    ...
}

 

위 코드는 getVerificationEmailStatus()를 통해 데이터를 직접 가져오고, setVerificationEmailStatus(2)를 통해 데이터를 직접 변경하고 있다.

 

아래 코드는 verifyEmail() 메서드를 통해 원래 기능을 한 곳에 모두 수행할 수 있도록 캡슐화했다.

 

public void verifyEmail(String token) {
    Member member = findByToken(token);
    if(member == null) throw new BadTokenException();
        
    member.verifyEmail();
    
    ...
}

public class Member {
    private int verificationEmailStatus;
    
    public void verifyEmail() {
        if(isEmailVerified()) 
            throw new AlreadyVerifiedExceptioin();
        else
            this.verificationEmailStatus = 2;
    }
    
    public boolean is EmailVerified() {
        return verificationEmailStatus == 2;
    }
}

 

참조

https://www.inflearn.com/course/%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%9E%85%EB%AC%B8/dashboard

 

객체 지향 프로그래밍 입문 - 인프런 | 강의

잘 하는 개발자가 되기 위해서는 유연한 코드를 작성할 줄 알아야합니다. 객체 지향을 이용해서 변경하기 좋은 유연한 코드를 만드는 방법을 알아보세요., 객체 지향 프로그래밍 입문 이번 '객

www.inflearn.com

반응형

'Programming > 기초지식' 카테고리의 다른 글

[객체 지향] 상속보단 조립  (0) 2021.10.22
[객체 지향] 다형성과 추상화  (0) 2021.10.22
[객체 지향] 캡슐화(Encapsulation)  (0) 2021.10.21
절차지향과 객체지향  (0) 2021.10.21
URI 그리고 URL  (0) 2021.09.03