캡슐화를 통해 내부의 구체적인 정보를 최대한 감춤
어떤 클래스의 메서드가 대부분 다른 클래스로 메서드 호출을 위임하면 중재자를 제거하고 직접 사용하도록 개선
Person - getManager 메서드를 보면 department 를 통한 manager 호출이 캡슐화 되어 있다
위임 숨기기의 반대로 getter 를 생성하여 department 를 접근하여 manager 를 호출하도록 변경
class Department {
private Person manager;
// ...getter, constructor
}
class Person {
private Department department;
private String name;
// ...constructor
public Person getManager() {
return this.department.getManager();
}
}
class Person {
private Department department;
private String name;
// ...constructor
// ...getManager 제거
public Department getDepartment() {
return this.department;
}
}
afterscroll 클래스에 상속을 제거하고 생성자에 위임
class CategoryItem {
private Integer id;
private String title;
private List<String> tags;
// ...getter, constructor
public boolean hasTag(String tag) {
return this.tags.contains(tag);
}
}
class Scroll extends CategoryItem {
private LocalDate dateLastCleaned;
public Scroll(Integer id, String title, List<String> tags, LocalDate dateLastCleaned) {
super(id, title, tags);
this.dateLastCleaned = dateLastCleaned;
}
public long daysSinceLastCleaning(LocalDate targetDate) {
return this.dateLastCleaned.until(targetDate, ChronoUnit.DAYS);
}
}
class Scroll {
private LocalDate dateLastCleaned;
private CategoryItem categoryItem;
public Scroll(Integer id, String title, List<String> tags, LocalDate dateLastCleaned) {
this.dateLastCleaned = dateLastCleaned;
this.categoryItem = new CategoryItem(id, title, tags);
}
public long daysSinceLastCleaning(LocalDate targetDate) {
return this.dateLastCleaned.until(targetDate, ChronoUnit.DAYS);
}
}
유연한 객체 생성을 위해 Booking 클래스에서 스테틱 팩토리 메서드를 이용
기존 서브클래스에 있던 기능들을 PremiumDelegation 에 옮긴 후 서브 클래스 제거
상속구조는 제거되고 PremiumDelegation 객체 생성 여부를 알고 있는 Booking
클래스에서 분기에 의해 처리되도록 코드 수정
class Booking {
protected Show show;
protected LocalDateTime time;
public Booking(Show show, LocalDateTime time) {
this.show = show;
this.time = time;
}
public boolean hasTalkback() {
return this.show.hasOwnProperty("talkback") && !this.isPeakDay();
}
protected boolean isPeakDay() {
DayOfWeek dayOfWeek = this.time.getDayOfWeek();
return dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY;
}
public double basePrice() {
double result = this.show.getPrice();
if (this.isPeakDay()) result += Math.round(result * 0.15);
return result;
}
}
class PremiumBooking {
private PremiumExtra extra;
public PremiumBooking(Show show, LocalDateTime time, PremiumExtra extra) {
super(show, time);
this.extra = extra;
}
@Override
public boolean hasTalkback() {
return this.show.hasOwnProperty("talkback");
}
@Override
public double basePrice() {
return Math.round(super.basePrice() + this.extra.getPremiumFee());
}
public boolean hasDinner() {
return this.extra.hasOwnProperty("dinner") && !this.isPeakDay();
}
}
class PremiumExtra {
private List<String> properties;
private double premiumFee;
// ...getPremiumFee, constructor
public boolean hasOwnProperty(String property) {
return this.properties.contains(property);
}
}
class Show {
private List<String> properties;
private double price;
// ...getPrice, constructor
public boolean hasOwnProperty(String property) {
return this.properties.contains(property);
}
}
// PremiumBooking 제거
class Booking {
protected Show show;
protected LocalDateTime time;
protected PremiumDelegation premiumDelegation;
public Booking(Show show, LocalDateTime time) {
this.show = show;
this.time = time;
}
public static Booking createBooking(Show show, LocalDateTime time) {
return new Booking(show, time);
}
public static Booking createPremiumBooking(Show show, LocalDateTime time, PremiumExtra extra) {
Booking booking = new Booking(show, time);
booking.premiumDelegation = new PremiumDelegation(new Booking(show, time), extra);
return booking;
}
public boolean hasTalkback() {
return (this.premiumDelegation != null) ? this.premiumDelegation.hasTalkback() :
this.show.hasOwnProperty("talkback") && !this.isPeakDay();
}
protected boolean isPeakDay() {
DayOfWeek dayOfWeek = this.time.getDayOfWeek();
return dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY;
}
public double basePrice() {
double result = this.show.getPrice();
if (this.isPeakDay()) result += Math.round(result * 0.15);
return (this.premiumDelegation != null) ? this.premiumDelegation.basePrice(result) : result;
}
public boolean hasDinner() {
return (this.premiumDelegation != null) ? this.premiumDelegation.hasDinner() : false;
}
}
class PremiumDelegation {
private Booking booking;
private PremiumExtra extra;
public PremiumDelegation(Booking booking, PremiumExtra extra) {
this.booking = booking;
this.extra = extra;
}
public boolean hasTalkback() {
return this.booking.show.hasOwnProperty("talkback");
}
public double basePrice(double result) {
return this.extra.getPremiumFee() + result;
}
public boolean hasDinner() {
return this.extra.hasOwnProperty("dinner") && !this.booking.isPeakDay();
}
}