도찐개찐
[코드디자인패턴-JAVA] Factory Method Pattern 본문
Factory Method Pattern
사용시점:
- 클래스가 자신이 생성할 객체의 클래스를 예측 할 수 없는 경우: 라이브러리나 프레임워크의 사용자가 제공하는 확장 클래스의 인스턴스를 생성해야 할 때 등에 사용됩니다.
- 클래스가 하위 클래스에 객체 생성 책임을 위임하고 싶은 경우: 객체 생성 로직을 하위 클래스에게 맡겨 다양한 객체 생성 방식을 구현
- 코드 중복 최소화: 공통 생성 로직을 부모 클래스에서 구현하고, 세부 로직은 하위 클래스에서 처리하면 코드 중복을 줄일 수 있습니다.
장점:
- 유연성 증가: Factory Method 패턴은 객체 생성과 사용을 분리하므로, 다양한 객체 생성 전략을 쉽게 교체하거나 확장 할 수 있습니다.
- 결합도 감소: 클라이언트가 특정 클래스와 직접적으로 결합 되지 않으므로, 코드의 유지보수와 확장성이 향상
- 확장성 향상: 새로운 객체 타입 추가 및 변경시 기존 코드를 수정하지 않고 새로운 팩토리 클래스만 추가하거나 변경하면 됩니다.
단점:
- 코드 복잡성 증가 다양한 팩토리와 제품 클래스가 필요하므로, 코드의 복잡성이 증가 할 수 있습니다.
- 디버깅 어려움: 객체 생성 로직이 분산되어 있을 경우, 디버깅이 어려워질 수 있습니다.
결론:
객체 생성 로직을 추상화하여 유연하고 확장 가능한 코드 작성할 수 있게 합니다. 하지만 복잡한 시스템에서는 코드의 복잡성이 증가 할 수 있으므로, 설계 시 주의가 필요합니다.
1. Referance 객체 생성
public abstract class Car {
public abstract void drive();
}
public abstract class Truck {
public abstract void drive();
}
public class Sedan extends Car {
@Override
public void drive() {
System.out.println("Driving a Sedan");
}
}
public class Suv extends Car {
@Override
public void drive() {
System.out.println("Driving a Suv");
}
}
public class FordSedan extends Sedan {
@Override
public void drive() {
System.out.println("Driving a Ford Sedan");
}
}
public class FordTruck extends Truck {
@Override
public void drive() {
System.out.println("Driving a Ford Truck");
}
}
public class BenzSedan extends Sedan {
@Override
public void drive() {
System.out.println("Driving a Benz Sedan");
}
}
public class BenzTruck extends Truck {
@Override
public void drive() {
System.out.println("Driving a Benz Truck");
}
}
2. Simple Factory 패턴
- 장점:
- 중앙 집중화: 객체 생성 로직이 하나의 메서드 또는 클래스 내에 집중 되므로, 생성 로직 변경이 필요할 때 한곳에서만 수정하면 됩니다.
- 재사용성: 클라이언트 코드에서 객체 생성 로직을 반복적으로 작성할 필요가 없으므로, 코드 중복을 줄일 수 있습니다.
- 간소화: 클라이언트는 팩토리 클래스에 요청만 하면 되므로, 객체 생성과 관련 된 복잡한 로직을 알필요가 없습니다.
- 단점:
- 개방/폐쇄 원칙(OCP) 위반: 새로운 객체 타입을 추가하거나 변경할 때마다 팩토리 클래스를 수정해야 하므로 OCP를 위반할 수 있습니다.
- 낮은 응집도: 팩토리 클래스가 너무 많은 종류의 객체 생성 로직을 담당하게 되면, 관리가 어려워 질 수 있으므로 응집도가 낮아 집니다.
- 유연성 제한: Simple Factory는 상대적으로 단순하므로, 복잡한 객체 생성 요구사항을 충족시키는데 제한이 있을 수 있습니다.
public class SimpleCarFactory {
public Car createCar(String type) {
Car car = null;
if (type.equals("Sedan")) car = new Sedan();
if (type.equals("Suv")) car = new Suv();
if (type.equals("FordSedan")) car = new FordSedan();
if (type.equals("BenzSedan")) car = new BenzSedan();
return car;
}
}
public class SimpleMain {
public static void main(String[] args) {
SimpleCarFactory simpleCarFactory = new SimpleCarFactory();
Car car = simpleCarFactory.createCar("FordSedan");
car.drive();
}
}
SimpleMain.main(null);
Driving a Ford Sedan
2. Factory Method 패턴
- 장점:
- 확장성: 새로운 클래스를 추가 할 때 기존 코드를 변경 불필요
- 낮은 결합도: 클라이언트와 구체 클래스간의 직접적인 의존성이 제거
- 유연성: 제품 클래스가 변경 되더라도 클라이언트 코드에 영향을 미치지 않음
- 단점:
- 복잡성 증가: 여러 팩토리 클래스가 필요할 수 있으며, 코드를 이해하고 유지하기 어려울 수 있습니다.
- 디버깅 난이도: 객체 생성 로직의 분산 되어 있는 경우 디버깅이 어려울 수 있습니다.
public abstract class FactoryCarFactory {
public abstract Car createCar();
}
public class SUVFactory extends FactoryCarFactory {
@Override
public Car createCar() {
return new Suv();
}
}
public class SedanFactory extends FactoryCarFactory {
@Override
public Car createCar() {
return new Sedan();
}
}
public class FactoryMain {
public static void main(String[] args) {
FactoryCarFactory carFactory = new SUVFactory();
Car car = carFactory.createCar();
car.drive();
}
}
FactoryMain.main(null);
Driving a Suv
3. Abstract Factory
- 장점:
- 제품 일관성: 관련 된 제품들이 함께 사용 되도록 보장하므로 일관성을 유지합니다.
- 확장성: 새로운 제품군을 쉽게 추가 할 수 있으며, 기존 클라이언트 코드를 수정 할 필요가 없습니다.
- 낮은 결합도: 구체적인 제품 클래스와 클라이언트 사이의 의존성을 줄이므로 코드의 유연성이 증가 합니다.
- 추상화 수준의 통일: 모든 제품군에 대해 동일한 추상 인터페이스를 제공하므로 클라이언트 코드의 복잡성을 줄일 수 있습니다.
- 단점:
- 유지보수 난이도: 너무 많은 클래스와 인터페이스가 있을 경우, 시스템을 이해하고 유지보수하기 어려워 질 수 있습니다.
- 복잡도 증가: 각 제품군별로 별도의 인터페이스와 구현 클래스를 제공해야 하므로, 코드 복잡도가 증가 할 수 있습니다.
- 런타임 에러 가능성: 제품 생성이 런타임에 이루어지므로, 잘못 된 팩토리를 사용하면 런타임 에러가 발생 될 수 있습니다.
결론:
- 다양한 제품군 간의 일관성과 확장성을 제공하는데 매우 유용합니다.
- 여러 제품군을 가지고 있고 이를 유연하게 관리해야 하는 시스템에서는 특히 효과적 입니다.
- 다만 이 패턴의 복잡성은 설계와 유지보수를 어렵게 만들 수 있으므로 실제 필요한 경우에만 적절히 사용해야 합니다.
public interface AbstractCarFactory {
Car createCar();
Truck createTruck();
}
public class FordFactory implements AbstractCarFactory {
@Override
public Car createCar() { return new FordSedan(); }
@Override
public Truck createTruck() { return new FordTruck(); }
}
public class BenzFactory implements AbstractCarFactory {
@Override
public Car createCar() { return new BenzSedan(); }
@Override
public Truck createTruck() { return new BenzTruck(); }
}
public class AbstractFactoryMain {
public static void main(String[] args) {
AbstractCarFactory fordAbstract = new FordFactory();
AbstractCarFactory benzAbstract = new BenzFactory();
Car fordCar = fordAbstract.createCar();
Truck benzTruck = benzAbstract.createTruck();
benzTruck.drive();
System.out.println("=============================");
fordCar.drive();
}
}
AbstractFactoryMain.main(null);
Driving a Benz Truck
=============================
Driving a Ford Sedan
728x90
'프로그래밍 > 코드디자인패턴' 카테고리의 다른 글
[코드디자인패턴-JAVA] Decorator Pattern (0) | 2024.02.29 |
---|---|
[코드디자인패턴-JAVA] Facade Pattern (0) | 2024.02.29 |
[코드디자인패턴-JAVA] Observer Pattern (0) | 2024.02.29 |
[코드디자인패턴-JAVA] Singleton Pattern (0) | 2024.02.29 |
[코드디자인패턴-JAVA] State Pattern (0) | 2024.02.29 |
Comments