본문 바로가기
Design Pattern

[Design Pattern] Builder 패턴/Prototype 패턴/Object pool 패턴

by happy coding! 2019. 6. 13.
반응형

Builder pattern

생성 인자가 많은 경우
객체 생성 로직을 클래스 밖으로 옮길 필요
서로 연관된 복잡한 생성자를 가지고 있을 때
생성자의 복잡성
비즈니스 룰의 복잡성
한번에 모든 생성 데이터가 없을 때
단계적 생성

package creation.builder;

public class NutritionFacts {

    // TODO
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;

    public static class Builder {

        private final int servingSize;
        private final int servings;
        private int calories;
        private int fat;
        private int sodium;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        // new Builder() -> Builder
        // (Builder).calories -> Builder
        // (Builder).fat
        public Builder calories(int val) {
            this.calories = val;
            return this;
        }

        public Builder fat(int val) {
            this.fat = val;
            return this;
        }

        // new Builder(1, 2).soldim(1).fat(2)
        public Builder sodium(int val) {
            this.sodium = val;
            return this;
        }

        // new Builder(1, 2).soldim(1).fat(2).build() -> NutritionFacts
        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }

    private NutritionFacts(Builder builder) {
        servingSize = builder.servingSize;
        servings = builder.servings;
        calories = builder.calories;
        fat = builder.fat;
        sodium = builder.sodium;

        System.out.println("객체 생성");
    }
}
package creation.builder;

public class Client {

    public static void main(String[] args) {

        // TODO
        NutritionFacts.Builder builder = new NutritionFacts.Builder(240, 8);
        builder.calories(100);
        builder.sodium(35);
        NutritionFacts n1 = builder.build();

        NutritionFacts n2 = new NutritionFacts
                .Builder(240, 8)
                .calories(100)
                .build();
    }

}

Prototype pattern

  • 런타임에 그 타입이 결정되는 거의 동일한 객체의 집합을 만들려고 할 때 적용

  • 새로운 인스턴스가 필요할 때 이미 생성된 인스턴스를 클론화하여 사용

    • DB에서 데이터를 가져와서 객체 생성하는 경우, 동일 데이터를 다시 DB에서 가져오기보다 이미 DB에서 데이터를 가져와서 생성된 객체를 복사해서 사용하면 효율적임
  • 인스턴스를 만드는 방법

    • New Something();
    • MyPart anotherMyPart = MyPartPrototype.clone();
  • Shallow clone vs Deep clone

    • Shallow clone (얕은 복사)

      • 기본형 타입 멤버 변수는 값을 복사
      • 사용자 정의 객체를 멤버변수로 가진 경우, 그 멤버변수는 clone시 참조 주소 값 복사
      • 즉, 복제된 객체 내의 사용자 정의 객체 멤버변수 변경시 원본 객체내의 사용자 정의 객체 멤버변수도 변경됨
    • Deep copy (깊은 복사)

      • 사용자 정의 객체의 멤버변수의 참조 주소값이 아닌 새로운 주소를 할당하여 값을 복제
package creation.prototype;

import java.util.ArrayList;
import java.util.List;

public class Users implements Cloneable {

    // TODO
    private List userList;

    public Users(List list) {
        this.userList = list;
    }

    public void loadData() {
        userList = new ArrayList();
        userList.add("yunyoung1819");
        userList.add("leekang");
    }

    public List getUserList() {
        return this.userList;
    }

    public Object clone() throws CloneNotSupportedException {
        // return super.clone();
        List temp = new ArrayList();
        for (Object s : this.userList) {
            temp.add((String) s);
        }

        return new Users(temp);
    }
}
package creation.prototype;

public class Client {

    public static void main(String[] args) throws CloneNotSupportedException {
        Users origin = new Users(null);
        origin.loadData();

        Users cloneU = (Users) origin.clone();

        if (origin.getUserList() == cloneU.getUserList())
            System.out.println("shallow");
        else
            System.out.println("deep");

        if (origin == cloneU)
            System.out.println("동일한 객체");
        else 
            System.out.println("복제된 객체");
    }

}

Object pool pattern

성능에 초점을 둔 패턴
DB Connection 생성은 expensive 하므로 사전에 생성된 객체를 재활용
reuse / share

package creation.pool;

import java.util.ArrayList;
import java.util.List;

public class ObjectPool<T> {

    // TODO
    private List<T> availablePool;
    private List<T> inUsePool;

    private int maxPoolSize = 10;

    public ObjectPool(Class<T> classObj) throws Exception {
        createPool(classObj, this.maxPoolSize);
    }

    public ObjectPool(Class<T> classObj, int maxPoolSize) throws Exception {
        this.maxPoolSize = maxPoolSize;
        createPool(classObj, maxPoolSize);
    }

    private void createPool(Class<T> classObj, int maxPoolSize) throws Exception {
        this.maxPoolSize = maxPoolSize;
        this.availablePool = new ArrayList<T>();
        this.inUsePool = new ArrayList<T>();

        for (int i = 0; i < maxPoolSize; i++) {
            this.availablePool.add(classObj.newInstance());
        }
    }

    public T getObject() {

        if (this.availablePool.size() == 0) {
            throw new PoolSizeOutException("사용할 객체가 없음");
        }

        T instance = this.availablePool.get(0);
        availablePool.remove(0);
        inUsePool.add(instance);

        return instance;
    }

    static class PoolSizeOutException extends RuntimeException {
        public PoolSizeOutException(String message) {
            super(message);
        }
    }

    public boolean invalidate(T obj) {
        for (T data:inUsePool) {
            if (data != null && data == obj) {
                return true;                
            }
        }
        return false;
    }
}
package creation.pool;

import creation.pool.ObjectPool.PoolSizeOutException;

public class Client {

    public static void main(String[] args) throws Exception {

        // TODO
        try {            
            ObjectPool<StringBuffer> pool 
            = new ObjectPool<StringBuffer>(StringBuffer.class, 2);

            StringBuffer o1 = pool.getObject();
            StringBuffer o2 = new StringBuffer(0);
            System.out.println(pool.invalidate(o1));
            System.out.println(pool.invalidate(o2));

            StringBuffer o3 = pool.getObject();
            StringBuffer o4 = pool.getObject();
        } catch (PoolSizeOutException e) {
            e.printStackTrace();
        }

    }

}
반응형

'Design Pattern' 카테고리의 다른 글

[Design pattern] 행위 패턴  (0) 2019.06.14
[Design pattern] 구조 패턴  (0) 2019.06.13
[Design Pattern] Singleton 패턴 / Factory 패턴  (0) 2019.06.13

댓글