ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Design Pattern] Builder 패턴/Prototype 패턴/Object pool 패턴
    Computer Science/Design Pattern 2019. 6. 13. 14:04
    반응형

    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();
            }
    
        }
    
    }
    반응형
Designed by Tistory.