반응형
Abstract Factory Pattern
- 추상 팩토리 패턴이란?
- 연관 있는 여러 객체 (제품) 군 (family) 의 생성을 추상화 한 생성 패턴
- 팩토리 메소드 패턴은 단일 객체 (제품) 의 생성을 추상화 한 것이라면, 추상 팩토리 패턴은 관련이 있는 여러 객체 (제품) 들의 일관된 생성을 추상화한 것
- 연관 있는 제품 군의 예시
- {Chair, Sofa, CoffeeTable} 에 대해 스타일 별로 각 제품을 일관되게 생성 해야 함
- 연관 있는 여러 객체 (제품) 군 (family) 의 생성을 추상화 한 생성 패턴
- 추상 팩토리 패턴
- 새로운 스타일의 제품 군이 추가되더라도 기존의 코드를 바꾸지 않고 추가할 수 있어야 함
- 제품 별로 인터페이스를 추상화 하고, 모든 추상 제품에 대한 생성 메소드를 가지는 팩토리로 추상화
- 각 서브 팩토리에서는 스타일에 연관된 제품군이 생성될 수 있도록 생성 메소드를 구현
- 새로운 스타일의 제품 군이 추가되더라도 기존의 코드를 바꾸지 않고 추가할 수 있어야 함
- 추상 팩토리 패턴의 구조
- 추상 팩토리 패턴 : Cross-platform GUI example
- 추상 팩토리 패턴 장단점
- 장점
- 객체를 생성하는 코드를 분리하여 클라이언트 코드와 결합도를 낮출 수 있음
- 제품 군 (family) 를 쉽게 대체할 수 있음
- SRP, OCP 준수함
- 단점
- 제품, 팩토리 들을 모두 구현해주어야 하기 때문에 코드 구조 복잡성이 높음 (팩토리 메소드 패턴과 동일)
- 새로운 제품 추가 시 모든 팩토리 구현 로직에 새로운 생성 함수가 추가되어야 함
- 장점
Builder Pattern
- 빌더 패턴이란?
- 복잡한 객체 생성 과정과 표현 방법을 분리하여 클라이언트가 다양한 구성을 조합하여 객체를 생성할 수 있도록 하는 생성 패턴
- 만약, 객체를 생성하고 초기화 하려고 할 때, 해당 클래스의 멤버 변수가 많은 경우에 모든 멤버 변수를 생성자에 넣어야 할까?
- 특정 객체 생성 시 모든 멤버 변수의 값이 쓰이지 않는다면?
- 빌더 패턴
- 클래스 내에서 객체 생성에 관련된 코드를 빼내서 Builder 라는 별도의 객체로 옮기고, Builder 를 이용하여 값을 설정 할 수 있게 함
- 복잡한 객체를 만드는 프로세스를 독립적으로 분리
HouseBuilder builder = new HouseBuilder(); House house1 = builder.buildWalls(4).buildDoors(1).getResult(); builder.reset(); House house2 = builder.buildWalls(8).buildDoors(2).buildWindows(4).getResult();
- 복잡한 객체를 만드는 프로세스를 독립적으로 분리
- 클래스 내에서 객체 생성에 관련된 코드를 빼내서 Builder 라는 별도의 객체로 옮기고, Builder 를 이용하여 값을 설정 할 수 있게 함
- 빌더 패턴의 구조
- 빌더 패턴의 구조 예시
- 빌더 패턴 구현 예시
public class House{ private int roofs; private int walls; private int windows; //getters and setters } public interface Builder{ void reset(); Builder setRoofs(int roofs); Builder setWalls(int walls); builder setWindows(int windows); } public class HouseBuilder implements Builder{ private House house; public HouseBuilder(){ this.house = new House(); } public void reset(){ this.house = new House(); } public Builder setRoofs(int roofs){ this.house.setRoofs(roofs); return this; } public Builder setWalls(int walls){ this.house.setWalls(walls); return this; } public Builder setWindows(int windows){ this.house.setWindows(windows); return this; } public House getResult(){ return this.house; } } public class Director{ public void makeSimpleHouse(Builder builder){ builder.reset(); builder.setRoofs(1); } public void makeComplexHouse(Builder builder){ builder.reset(); builder.setRoofs(4).setWalls(4).setWindows(4); } } public class Client{ public static void main(String[] args){ Director director = new Director(); HouseBuilder builder = new HouseBuilder(); director.makeSimpleHouse(builder); House simpleHouse = builder.getResult(); director.makeComplexHouse(builder); House complexHouse = builder.getResult(); } }
- 빌더 패턴 사용 예시
public class StringBuilderExample{ public static void main(String[] args){ StringBuilder stringBuilder = new StringBuilder(); String result = stringBuilder.append("whiteship").append("keesun").toString(); System.out.println(result); } } public class StreamExample{ public static void main(String[] args){ Stream.Builder<String> stringStreamBuilder = Stream.builder(); Stream<String> names = stringStreamBuilder.add("keesun").add("whiteship").build(); names.forEach(System.out::println); } }
- 빌더 패턴 장단점
- 장점
- 구성하기 복잡한 객체를 순차적으로 만들 수 있음
- 복잡한 객체를 만드는 구체적인 과정을 숨길 수 있음
- 동일한 프로세스를 통해 구성에 따라 다른 객체를 만들 수 있음
- 불완전한 객체를 사용하지 못하도록 방지할 수 있음
- 단점
- 선행적으로 빌더 객체를 먼저 만들어야 원하는 객체를 만들 수 있음
- 객체 생성을 위한 코드 대비 구조적으로 복잡해짐
- 간단한 객체는 생성자를 통해서 만드는게 좋음
- 장점
Prototype Pattern
- 프로토타입 패턴이란?
- 기존의 객체를 복제 (clone) 하여 새로운 객체를 만드는 생성 패턴
- 클래스에 의존하지 않으면서 기존 객체를 복사
- 원형이 되는 (prototypical) 인스턴스를 사용하여 생성할 객체의 종류를 명시하고, 이렇게 만든 견본을 복사해서 새로운 객체를 생성
- 객체 생성/복사가 까다로울 수 있는 상황
- private/protected 멤버 변수 때문에 클래스 외부에서 객체를 복사하지 못할 수 있음
- 객체 생성에 따른 리소스가 많이 요구될 때 새로 생성하는 것은 비효율
- 기존의 객체를 복제 (clone) 하여 새로운 객체를 만드는 생성 패턴
- 프로토타입 패턴의 구조
- 복제되는 실제 객체에 복제 프로세스를 위임함 (clone 이라는 공통 인터페이스를 가지게 함)
- 프로토타입 패턴 구현 예시
- Cloneable 인터페이스 (in java)
- 자바에서 Objects.clone() 메소드는 인스턴스 객체의 복제를 위한 메소드
- 해당 인스턴스를 복제하여 새로운 인스턴스를 생성해 레퍼런스를 반환
- clone() 메소드를 사용하려면 Cloneable 인터페이스를 implements 하고 clone() 메소드를 오버라이딩 해주어야 함 (Prototype 인터페이스 역할)
import java.lang.Cloneable; class Person implements Clonable{ //멤버 변수... //clone 메소드를 오버라이딩 public Object clone() throws CloneNotSupportedException{ // 기본적으로 부모의 clone 을 그대로 불러와 반환 (Shallow copy) return super.clone(); } } public class Main{ public static void main(String[] args){ try{ Person p = new Person("James", 11); Person p_copy = (Person)p.clone(); }catch (Exception e){} } }
public class Team implements Cloneable { String teamName; List<Employee> employeeList; public Team(String teamName) { this.teamName = teamName; this.employeeList = new ArrayList<>(); } public void addEmployee(Employee employee) { employeeList.add(employee); } public List<Employee> getEmployeeList() { return employeeList; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); // 얕은 복사 수행 } } public class Employee { String name; public Employee(String name) { this.name = name; } @Override public String toString() { return "Employee{name='" + name + "'}"; } } public class Client { public static void main(String[] args) throws CloneNotSupportedException { Team firstTeam = new Team("firstTeam"); firstTeam.addEmployee(new Employee("James")); firstTeam.addEmployee(new Employee("Ted")); Team copyTeam = (Team) firstTeam.clone(); // shallow copy System.out.println("Are they the same instance? => " + (firstTeam == copyTeam)); // false System.out.println("Do they have the same content? => " + (firstTeam.equals(copyTeam))); // true System.out.println("firstTeam's members: " + firstTeam.getEmployeeList()); System.out.println("copyTeam's members: " + copyTeam.getEmployeeList()); firstTeam.getEmployeeList().set(0, new Employee("Gale")); System.out.println("\nAfter modification:"); System.out.println("firstTeam's members: " + firstTeam.getEmployeeList()); System.out.println("copyTeam's members: " + copyTeam.getEmployeeList()); } }
- Shallow copy (얕은 복사) v.s. deep copy (깊은 복사)
- Cloneable 인터페이스 (in java)
- 프로토타입 패턴 장단점
- 장점
- 프로토타입 패턴을 사용하면 객체를 생성하는 복잡한 과정을 피할 수 있음
- 객체를 복제하는 것이 객체를 새로 생성하는 것보다 일반적으로 더 빠름
- 런타임에 객체의 타입을 동적으로 변경하거나 새로운 객체 유형을 추가하는 데 유용
- 단점
- 객체가 복잡한 구조를 가지고 있거나 객체 간에 서로 참조가 있을 때, 객체 복제 과정이 복잡해질 수 있음
- 얕은 복사(객체의 필드만 복제)와 깊은 복사(참조된 객체도 복제)를 관리해야 할 수 있음
- 프로토타입 패턴은 객체를 복제하므로 남발 시 메모리 사용량이 늘어날 수 있음
- 객체 복제로 인해 객체의 상태 관리가 어려워질 수 있음
- 객체가 복잡한 구조를 가지고 있거나 객체 간에 서로 참조가 있을 때, 객체 복제 과정이 복잡해질 수 있음
- 장점
반응형
'3학년 2학기 학사 > 소프트웨어 분석 및 설계' 카테고리의 다른 글
[소프트웨어 분석 및 설계] L19. Facade Pattern, Flyweight Pattern, Proxy Pattern (0) | 2024.12.13 |
---|---|
[소프트웨어 분석 및 설계] L18. Composite Pattern, Decorator Pattern (0) | 2024.12.13 |
[소프트웨어 분석 및 설계] L17. Adapter Pattern, Bridge Pattern (3) | 2024.12.13 |
[소프트웨어 분석 및 설계] L15. Factory Method (팩토리 메소드) (0) | 2024.12.12 |
[소프트웨어 분석 및 설계] # L14. 디자인 패턴, 싱글톤 패턴 (0) | 2024.12.11 |