회사에서 소프트웨어 회사에 특화된 영업관리 모듈을 설계하고 개발하는 업무를 맡았다.
N개
의 고객사의 비즈니스에 맞게 ERP시스템을 설계하고 개발해야했다.
표준이 되는 패키지 서비스를 갖고 모든 업체의 비즈니스를 소화해야하기 때문에 무지성으로 만들면, 업체 전용으로 프로젝트가 과생산 되는 경우가 발생했다.
이렇게 되면, 향후 업체가 늘어날수록 유지보수가 힘들어지고
, 추가공수
가 발생하는 문제가 생긴다.
예를 들면, A업체
는 전자계약으로 글로사인
사용하고, B업체
는 스마트빌
을 사용할 수 있다.
각 전자계약 업체마다 API가 다르니 업체 전용프로젝트를 만들어서 전용으로 나가는 방식을 채택하게 되면 향후에는 OO전자계약을 사용하는
회사 N개에 N개의 무지성 클론프로젝트가 생기는 것이다.
이를 효율적으로 확장
하기 위해 여러가지로 찾아보다가 팩토리패턴
으로 패키지서비스를 설계했다.
Product
: 생성할 객체의 인터페이스 또는 상위 클래스.ConcreteProduct
: 실제로 생성되는 객체.Factory
: 객체를 생성하는 클래스 또는 메서드./* 각 전자계약의 Product */
public interface eContract {
void makeContract(contractModel contract); //전자계약에 필요한 변수들을 총망라한 모델 - ERP데이터를 기반으로 만들어진다.
}
/*******************************************************************/
/* 각 전자계약의 ConcreteProduct 구현체 */
@Component
public class Glosign implements eContract { //글로사인
@Override
public void makeContract(contractModel contract) {
//글로사인 api호출 로직
}
}
@Component
public class Smartbill implements eContract { //스마트빌
@Override
public void makeContract(contractModel contract) {
//스마트빌 api 호출 로직
}
}
/*******************************************************************/
/* 각 전자계약의 Factory Bean*/
@Component
public class ContractFactory {
private final Map<String, eContract> contractMap = new HashMap<>();
//생성자주입 - 빌드시 스프링컨텍스트에 위의 구현체를 바탕으로 자동으로 주입
//팩토리에 구현해놓은 전자계약 클래스들을 등록하는 과정(등록기반팩토리)
public ContractFactory(List<eContract> eContracts) {
for (eContract econtract : eContracts) {
contractMap.put(econtract.getClass().getSimpleName().toLowerCase(), econtract);
}
}
public eContract getEContract(String type) {
return contractMap.get(type.toLowerCase());
}
}
/*******************************************************************/
// 클라이언트 코드
@RestController
public class ContractController {
private final ContractFactory contractFactory;
public ContractController(ContractFactory contractFactory) {
this.contractFactory = contractFactory;
}
@GetMapping("/contract")
public void contract(@RequestParam String type, @RequestParam contractModel contract) {
eContract econtract = contractFactory.getEContract(type);
if (payment != null) {
econtract.makeContract(amount); //구현해놓은 전자계약 클래스에 따라 다른 api작동
} else {
throw new IllegalArgumentException("Unknown payment type: " + type);
}
}
}
/*******************************************************************/
개방폐쇄원칙(OCP)
에도 좋다고 한다. 확장에는 열려있고, 수정에는 닫혀있다는 의미다.