
https://refactoring.guru/design-patterns/java
package singleton;
import java.time.LocalDateTime;
// app 전체에서 log 를 담당하는 클래스
// 이 클래스의 객체는 단 한개만 만들어서 사용되도록 한다.
public class Logger {
// static {
// // 미리 선 작업...
// logger = new Logger();
// }
// private static Logger 변수
// private static Logger Logger = new Logger();
private static Logger logger;
// 생성자를 private 로
private Logger() {}
// static 메소드로 외부에서 객체를 얻을 수 있는 방법 제공
public static Logger getInstance() {
if (logger == null) {
logger = new Logger();
}
return logger;
}
public void log(String message) {
LocalDateTime ldt = LocalDateTime.now();
String date = ldt.getYear() + "/" + ldt.getMonthValue() + "/" + ldt.getDayOfMonth();
String time = ldt.getHour() + ":" + ldt.getMinute() + ":" + ldt.getSecond();
System.out.println("[" + date + " " + time + "] " + message);
}
}
// 객체는 만들어진다. static으로 정적으로 할 뿐
package singleton;
public class Test {
public static void main(String[] args) {
// Logger logger = new Logger();
// Logger logger2 = new Logger();
// 객체를 만들던가 x
// static ???
Logger logger = Logger.getInstance();
System.out.println(logger);
logger.log("첫 번째 로그입니다.");
m();
}
public static void m() {
Logger logger = Logger.getInstance();
System.out.println(logger);
logger.log("두 번째 로그입니다.");
}
}
package methodchain;
public class Calculator {
private int first;
private int second;
public Calculator setFirst(int first) {
this.first = first;
return this;
}
public Calculator setSecond(int second) {
this.second = second;
return this;
}
public Calculator showAdd() {
System.out.println("Add " + this.first + " + " + this.second + " = " + (this.first + this.second));
return this;
}
public Calculator showSub() {
System.out.println("Sub " + this.first + " - " + this.second + " = " + (this.first - this.second));
return this;
}
}
package methodchain;
public class Test {
public static void main(String[] args) {
Calculator calc = new Calculator();
// // 3 + 5
// calc.setFirst(3);
// calc.setSecond(5);
// calc.showAdd();
// // 3 - 1
// calc.setFirst(3);
// calc.setSecond(1);
// calc.showSub();
// // 6 - 1
// calc.setFirst(6);
// calc.showSub();
// method chain
calc.setFirst(3).setSecond(5).showAdd().setSecond(1).showSub();
// StringBuilder
StringBuilder sb = new StringBuilder();
sb.append("abc");
sb.append("def");
sb.append("123")
.append("456")
.append("789");
}
}
package iterator;
public interface Container {
Iterator getIterator();
}
package iterator;
public interface Iterator {
boolean hasNext();
Object next();
}
package iterator;
public class StringContainer implements Container {
String[] strArray = {"Hello", "Iterator", "Pattern"};
@Override
public Iterator getIterator() {
// Iterator interface 를 구현한 객체를 return
return new StringIterator();
}
private class StringIterator implements Iterator {
int index; // default 0
@Override
public boolean hasNext() {
if (index < strArray.length) return true;
return false;
}
@Override
public Object next() {
// 사용자가 hasNext() 후 호출
// return strArray[index++];
// 좀 더 안전한 방법
if (this.hasNext()) return strArray[index++];
return null;
}
}
}
package iterator;
public class Test {
public static void main(String[] args) {
StringContainer container = new StringContainer();
Iterator iter = container.getIterator();
while (iter.hasNext()) {
System.out.println(iter.next());
}
}
}
package factory;
public interface Transportation {
void move();
}
package factory;
public class Car implements Transportation {
@Override
public void move() {
System.out.println("자동차가 달립니다.");
}
}
package factory;
public class SportsCar implements Transportation {
@Override
public void move() {
System.out.println("스포츠카가 달립니다.");
}
}
package factory;
public class Airplane implements Transportation {
@Override
public void move() {
System.out.println("비행기가 날아갑니다.");
}
}
package factory;
public class Hellicopter implements Transportation {
@Override
public void move() {
System.out.println("헬리콥터가 날아갑니다.");
}
}
package factory;
// XXXFactory 보통 Singleton 으로 구성
public class TransportationFactory {
public static Transportation getTransportation(String clsf) {
Transportation t = null;
switch(clsf) {
case "Air": t = new Airplane(); break;
case "Car": t = new SportsCar(); break;
}
return t;
}
}
package factory;
public class Test {
public static void main(String[] args) {
// 사용하는 쪽인 Test 가 Car 클래스를 인지하고 있어야 한다.
// Car 대신 SportsCar 로 변경되는 경우 코드를 변경해야 한다.
// Car car = new Car();
// SportsCar car = new SportsCar();
// 만들어진 객체가 Car(), SportsCar() 객체이든 Transportation 인터페이스에 있는
// 메소드만 사용
// Transportation car = new Car();
// Transportation car = new SportsCar();
// Car, Airplane 클래스를 몰라도 문자열로 필요한 객체를 얻을 수 있다.
// 이 객체는 Transportation interface 를 구현한 것만 알고 있고 그것만 사용
Transportation t = TransportationFactory.getTransportation("Air");
t.move();
Transportation t2 = TransportationFactory.getTransportation("Car");
t2.move();
}
}
package adapter;
public interface LegacyFunc {
int calc(int num);
}
package adapter;
public interface LegacyFuncAdapter {
int calc(int num);
}
package adapter;
public class LegacyFuncImpl implements LegacyFunc {
@Override
public int calc(int num) {
// Legacy 는 x 10
return num * 10;
}
}
package adapter;
public class LegacyFuncAdapterImpl implements LegacyFuncAdapter {
// 기존 Legacy interface 및 구현체를 이용
private LegacyFunc legacyFunc;
public LegacyFuncAdapterImpl(LegacyFunc legacyFunc) {
this.legacyFunc = legacyFunc;
}
// legacy 의 결과를 이어서 추가로 처리할 내용
private int convertLegacyData(int legacyResult) {
System.out.println(legacyResult);
return legacyResult * 2;
}
@Override
public int calc(int num) {
// Legacy 는 x 10
return convertLegacyData(legacyFunc.calc(num));
}
}
package adapter;
public class Test {
public static void main(String[] args) {
// Legacy system 처리
// LegacyFunc legacyFunc = new LegacyFuncImpl();
// System.out.println(legacyFunc.calc(10));
// New system 처리
LegacyFunc legacyFunc = new LegacyFuncImpl();
LegacyFuncAdapter legacyFuncAdapter = new LegacyFuncAdapterImpl(legacyFunc);
System.out.println(legacyFuncAdapter.calc(10));
}
}
package builder;
public class NormalBook {
private String isbn;
private String title;
private String author;
private String description;
private int price;
public NormalBook() {}
public NormalBook(String isbn, String title, String author, String description, int price) {
super();
this.isbn = isbn;
this.title = title;
this.author = author;
this.description = description;
this.price = price;
}
public NormalBook(String isbn, String title, String author) {
super();
this.isbn = isbn;
this.title = title;
this.author = author;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "NormalBook [isbn=" + isbn + ", title=" + title + ", author=" + author + ", description=" + description
+ ", price=" + price + "]";
}
}
package builder;
// slim 버전
public class BuilderBook {
private String isbn;
private String title;
private String author;
private String description;
private int price;
public BuilderBook() {}
public static BuilderBook builder() {
return new BuilderBook();
}
public BuilderBook isbn(String isbn) {
this.isbn = isbn;
return this;
}
public BuilderBook title(String title) {
this.title = title;
return this;
}
public BuilderBook author(String author) {
this.author = author;
return this;
}
public BuilderBook description(String description) {
this.description = description;
return this;
}
public BuilderBook price(int price) {
this.price = price;
return this;
}
@Override
public String toString() {
return "BuilderBook [isbn=" + isbn + ", title=" + title + ", author=" + author + ", description=" + description
+ ", price=" + price + "]";
}
}
package builder;
public class Board {
private String title;
private String content;
private String category;
public Board(Builder builder) {
this.title = builder.title;
this.content = builder.content;
this.category = builder.category;
}
@Override
public String toString() {
return "Board [title=" + title + ", content=" + content + ", category=" + category + "]";
}
// Board 를 사용하는 쪽에 먼저 노출되어 가짜 set 작업을 수행한 후, 마지막에 build() 호출되면 진짜 Board 객체를 생성해서 return 한다.
public static class Builder {
private String title;
private String content;
private String category;
public Builder title(String title) {
this.title = title;
return this;
}
public Builder content(String content) {
this.content = content;
return this;
}
public Builder category(String category) {
this.category = category;
return this;
}
public Board build() {
return new Board(this);
}
}
}
package builder;
public class Test {
public static void main(String[] args) {
NormalBook nBook = new NormalBook();
nBook.setIsbn("111");
nBook.setTitle("제목1");
NormalBook nBook2 = new NormalBook("222", "이길동", "제목2"); // 순서 오류
// 적당한 filed 를 set 할 수 있는 적당한 생성자를 추가로 요구
BuilderBook bBook = BuilderBook.builder()
.title("제목2")
.isbn("222")
.author("이길동");
System.out.println(bBook);
// Board
Board board = new Board.Builder()
.title("제목3")
.content("제목3")
.category("분류1")
.build();
System.out.println(board);
}
}
import java.util.Date;
public class _01_Parameter_Object {
// Old
static class CustomerOld{
public int getOrderAmount(Date from, Date to) { return 0; }
public int getCancelAmount(Date from, Date to) { return 0; }
public int getCartAmount(Date from, Date to) { return 0; }
}
// New
static class CustomerNew{
public int getOrderAmount(FromTo fromTo) { return 0; }
public int getCancelAmount(FromTo fromTo) { return 0; }
public int getCartAmount(FromTo fromTo) { return 0; }
}
static class FromTo{
Date from;
Date to;
}
}
public class _02_Parameterize_Method {
// Old
static class EmployeeOld{
public void raiseSalary10Percentage() {}
public void raiseSalary20Percentage() {}
public void raiseSalary50Percentage() {}
}
// New
static class EmployeeNew{
public void raiseSalaryPercentage(int percentage) {}
}
}
public class _03_Preserve_Whole_Object {
static class Today{
int getLow() { return 0; }
int getHigh() { return 0; }
}
static void calcLowHigh() {
Today today = new Today();
int low = today.getLow();
int high = today.getHigh();
checkWeatherOld(low, high);
}
static void checkWeatherOld(int low, int high) {}
static void checkWeatherNew(Today today) {}
}
public class _04_Consolidate_Conditional_Expression {
// Old
public void registerOld(String userName, String userPassword, String userEmail) {
if( userName.contains("aaa")) stopRegister();
if( userPassword.contains("bbb")) stopRegister();
if( userEmail.contains("ccc")) stopRegister();
doRegister();
}
public void stopRegister() {}
public void doRegister() {}
// New
public void registerNew(String userName, String userPassword, String userEmail) {
if( registerValidate(userName, userPassword, userEmail)) doRegister();
stopRegister();
}
public boolean registerValidate(String userName, String userPassword, String userEmail) {
if( userName.contains("aaa")) return false;
if( userPassword.contains("bbb")) return false;
if( userEmail.contains("ccc")) return false;
return true;
}
}
public class _05_Consolidate_Duplicate_Conditional_Fragments {
public static void sendToCustomer(int customerId, int price) { }
public static int getSaledPrice() { return 0; }
public static int getRegularPrice() { return 0; }
public static boolean isTodayInSale() { return false; }
// Old
public static void calculatePriceOld() {
int customerId = 100;
int price = 0;
if( isTodayInSale() ) {
price = getSaledPrice();
sendToCustomer(customerId, price);
}else {
price = getRegularPrice();
sendToCustomer(customerId, price);
}
}
// New
public static void calculatePriceNew() {
int customerId = 100;
int price = 0;
// if( isTodayInSale() ) {
// price = getSaledPrice();
// }else {
// price = getRegularPrice();
// }
// 3항 연산자 조건 ? _ : _
price = isTodayInSale() ? getSaledPrice() : getRegularPrice();
sendToCustomer(customerId, price);
}
}
public class _06_Decompose_Conditional {
//Old
public static int calcOld(int val1, int val2, int val3) {
int result = 0;
if( (val1 < 100 && val3 > 200) || val1 == 100 && val2 == 200 ) {
result = val1*val2 - val3;
}else {
result = val2 + val3 - val1;
}
return result;
}
// New
public static int calcNew(int val1, int val2, int val3) {
int result = 0;
if( checkValue(val1, val2, val3) ) {
result = calcResultOne(val1, val2, val3);
}else {
result = calcResultTwo(val1, val2, val3);
}
return result;
}
public static boolean checkValue(int val1, int val2, int val3) {
if( (val1 < 100 && val3 > 200) || val1 == 100 && val2 == 200 ) return true;
return false;
}
public static int calcResultOne(int val1, int val2, int val3) {
return val1 * val2 - val3;
}
public static int calcResultTwo(int val1, int val2, int val3) {
return val2 + val3 - val1;
}
}
public class _07_Reverse_Conditional {
public static boolean isEven(int num) { return false; }
public static boolean isOdd(int num) { return false; }
// Old
public static void calcOld(int num) {
if( !isEven(num) ) {
}else {
}
}
// New
public static void calcNew(int num) {
if( isOdd(num) ) {
}else {
}
}
}
public class _09_Separate_Query_From_Modifier {
// Old
public static String getUserNameChangeUserState(int userId) {
// 사용자 이름도 전달, 사용자의 상태값도 변경
return "userName";
}
// New
public static String getUserName() {
return "userName";
}
public void changeUserState() {}
}
public class _10_Extract_Class {
// Old
static class CustomerOld{
String userName;
// hobby
boolean loveFootball;
String favoriatePlayer;
}
// New
static class CustomerNew{
String userName;
Hobby hobby;
}
static class Hobby {
boolean loveFootball;
String favoriatePlayer;
}
}
// java : Class : Customer, Order, Board ==> DB Table customer table, order table, board table
public class _11_Extract_Interface {
// Old
static class DogOld{
void run() {}
void eat() {}
}
static class BirdOld{
void fly() {}
void eat() {}
}
static class DuckOld{
void fly() {}
void run() {}
void eat() {}
}
// 개별 클래스의 메소드들 중 동일한 기능을 수행하는 (설사 클래스가 서로 동일하지 않은(상송 관계에 없는)) 경우라면 인터페이스로 분리
// eat -> Eatable, run -> Runnable, fly -> Flyable
// New
static interface Eatable { void eat(); }
static interface Runnable { void run(); void runFaster();}
static interface Flyable { void fly(); }
static class DogNew implements Eatable, Runnable {
public void run() {}
public void eat() {}
@Override
public void runFaster() {
// TODO Auto-generated method stub
}
}
static class BirdNew implements Flyable, Eatable {
public void fly() {}
public void eat() {}
}
static class DuckNew implements Flyable, Eatable {
public void fly() {}
public void run() {}
public void eat() {}
}
}