๊ฐ์ฒด์ ์์ฑ ์ฑ ์์ ์ถ์ ํด๋์ค(or ์ธํฐํ์ด์ค)์ ๋ฉ์๋์ ๋งก๊ธฐ๋ ํจํด์ด๋ค.
์๋ฅผ ๋ค์ด ์ฐจ๋ฅผ ๋ง๋๋ ๊ณต์ฅ์ด ์๋ค. ์ต์ด์๋ ์๋ฐ๋ผ๋ง ์ฐ์ด๋์๋๋ฐ. ๊ณต์ฅ์ด ๋๋ฌด ์๋ผ์ G70, GV80 ๋ฑ ์๋ก์ด ์ฐจ ๋ผ์ธ์ด ํ์ํ๋ค. ํ์ง๋ง ์ฐจ๋ ๊ธฐ๋ณธ์ ์ธ ๋ถํ์ ์ค์ ํ๋ ๊ฒ์ ๋์ผํ๋ค. ํ์ง๋ง ์ฐจ๋์ ๋งํฌ๋ผ๋์ง ๋ฐํด๋ผ๋์ง ๋ค๋ฅด๊ฒ ์ ์ฉ์ด ํ์ํ ๋ถ๋ถ์ด ์๋ค.
์ด๋ฅผ ์ฝ๋๋ก์จ ๋ฌด์ํ๊ฒ ํด๊ฒฐํ๋ฉด
if(car.name.equals("์๋ฐ๋ผ")){
...
}else if(car.name.equals("GV80")){
...
}else if(car.name.equals("G70")){
...
}
๊ณผ ๊ฐ๊ฑฐ๋ ๋ ์ฌ๊ฐํ๊ฒ ๋ถ๊ธฐ์ฒ๋ฆฌ๋๋ ์ฝ๋๋ฅผ ์์ฑํ ์ง๋ ๋ชจ๋ฅธ๋ค.
ํ์ง๋ง ์ด๋ฐ ์ฝ๋๋ฅผ ์ง๋ฉด ์๋์ ํ๋ฆ์ ๋ง๊ฒ ๋ค๋น๊ฒ์ด์ ์ ์ผ๊ด์ ์ผ๋ก ์ ์ฉํ๋ค๋์ง ์ฐจ์ ๋ก๊ณ ๋ฅผ ๋ณ๊ฒฝํ๋ค๋์ง ๋ฑ์ ์์ ์ด ์๊ธฐ๋ฉด ์ฝ๋๊ฐ ๋ชจ๋ ์์ ์ด ์ผ์ด๋๋ค.
๊ทธ๋์ ์ฐ๋ฆฌ๋ Factory Method Pattern
์ ์ด์ฉํ์ฌ ์ข ๋ OPC๋ฅผ ์งํค๋ ์ฝ๋๋ก ํ์์์ผ๋ณด์.
public class Car {
private String name;
private String color;
private String logo;
private String engine;
... getter, setter, toString
}
Car๋ผ๋ class๋ฅผ ๋ง๋๋ ค๋ฉด ์๋์ฐจ ์ด๋ฆ๊ณผ ์์ง์ ์ ์ํด์ผํ๋ค๊ณ ํ์.
public class AvanteFactory {
public static Car createCar(String owner, String color){
// validate
if(owner.isEmpty()) throw new IllegalArgumentException("์์ ์๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.");
if(color.isEmpty()) throw new IllegalArgumentException("์์์ ์
๋ ฅํด์ฃผ์ธ์.");
System.out.println("Avante ์์ฐ์ ์์ํฉ๋๋ค.");
Car car = new Car();
car.setOwner(owner);
System.out.println("Avante ์์ฐ์ค...");
car.setEngine("v1");
car.setColor(color);
car.setLogo("ํ๋");
car.setName("Avante");
System.out.println("Avante๋ฅผ ๋ง๋๋๋ฐ ์ฑ๊ณตํ์ต๋๋ค.");
return car;
}
}
public class GV80Factory {
public static Car createCar(String owner, String color){
// validate
if(owner.isEmpty()) throw new IllegalArgumentException("์์ ์๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.");
if(color.isEmpty()) throw new IllegalArgumentException("์์ญ์ ์
๋ ฅํด์ฃผ์ธ์.");
System.out.println("GV80 ์์ฐ์ ์์ํฉ๋๋ค.");
Car car = new Car();
car.setOwner(owner);
System.out.println("GV80 ์์ฐ์ค...");
car.setEngine("v1+");
car.setColor(color);
car.setLogo("์ ๋ค์์ค");
car.setName("GV80");
System.out.println("GV80์ ๋ง๋๋๋ฐ ์ฑ๊ณตํ์ต๋๋ค.");
return car;
}
}
๊ทธ๋ฆฌ๊ณ Car๋ฅผ ๋ง๋ค์ด์ ๋ฐํ์์ผ์ฃผ๋ factory class๋ค์ ์ ์ํ๋ค.
public class Client {
public static void main(String[] args) {
Car car1 = AvanteFactory.createCar("์ต์คํธ", "white");
Car car2 = GV80Factory.createCar("์ต์คํธ", "black");
System.out.println(car1.toString());
System.out.println(car2.toString());
}
}
๊ทธ๋ฆฌ๊ณ ์ฐจ๋ฅผ ๋ง๋ค๋ฉด
๋ค์๊ณผ ๊ฐ์ด ์ฐจ๋์ ์ ์์ ์ผ๋ก ์์ฐํด๋ผ ์ ์๋ค. ํ์ง๋ง ์ฌ๊ธฐ์๋ ๋ฌธ์ ๊ฐ ์๋๋ฐ. ๋ง์ฝ ๋ค๋น๊ฒ์ด์ ์ ์ถ๊ฐ๋ก ๋ฌ์์ผํ ๊ฒฝ์ฐ factory class๋ง๋ค ์ฐพ์๊ฐ์ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํด์ผํ๋ฉฐ, ์ฐจ๋ ์์ฐ์ ์ํด ์งํ๋๋ ๊ณผ์ ์ด ์ค๋ณต๋์ด ์ ์ง๋ณด์๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ์๋ ๋ชจ๋ factory class์ ์ฝ๋์ ์์ ์ด ๋ฐ์ํ๋ค๋ ์ ์ด๋ค.
public interface CarFactory {
default Car orderCar(String owner, String color){
validate(owner, color);
Car car = createCar();
prepare(car);
settingCar(car, owner, color);
complete(car);
return car;
}
private void validate(String owner, String color){
if(owner.isEmpty()) throw new IllegalArgumentException("์์ ์๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.");
if(color.isEmpty()) throw new IllegalArgumentException("์์์ ์
๋ ฅํด์ฃผ์ธ์.");
}
private void prepare(Car car){
System.out.println(car.getName()+" ์์ฐ์ ์์ํฉ๋๋ค.");
System.out.println(car.getName()+" ์์ฐ์ค...");
}
private void settingCar(Car car, String owner, String color){
car.setOwner(owner);
car.setColor(color);
}
private void complete(Car car){
System.out.println(car.getName()+"์ ๋ง๋๋๋ฐ ์ฑ๊ณตํ์ต๋๋ค.");
}
// ๊ตฌํํด์ผํ๋ ๋ถ๋ถ
Car createCar();
}
๋ค์๊ณผ ๊ฐ์ด interface๋ฅผ ์์ฑํ๋ฉฐ ์ฝ๋ ๋ฆฌํฉํ ๋ง์ ์งํํด๋ณด์๋ค. ์ค๋ณต์ฒ๋ฆฌ ๋๋ ๋ถ๋ถ์ ๋ชจ๋ interface ๋ด method๋ก ๋นผ๊ณ ์ค์ ๋ก ๊ตฌํํด์ผํ ๋ถ๋ถ์ธ createCar()
method๋ง ๊ตฌํ class์์ ์ ์ํ๋ฉด ๋๋ค.
interface์์ private method๋ java9 ์ด์์์ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ฏ๋ก java 8์ ์ฌ์ฉํ๋ค๋ฉด ์ค๊ฐ์ interface๋ฅผ ๊ตฌํํ๋ ์ถ์ ํด๋์ค๋ฅผ ์์ฑํ์ฌ ๋ฃ์ด์ฃผ์ด์ผํ๋ค. ๊ทธ๋ฆฌ๊ณ ๊ทธ ์ถ์ ํด๋์ค๋ฅผ ๋ค๋ฅธ ๊ตฌํ ํด๋์ค๋ค์ด ๋ค์ ๊ตฌํํด์ฃผ์ด์ผํ๋ค.
public class AvanteV2 extends Car {
public AvanteV2() {
setName("Avante");
setEngine("v2");
setLogo("ํ๋");
}
}
public class AvanteFactoryV2 implements CarFactory{
@Override
public AvanteV2 createCar() {
return new AvanteV2();
}
}
๊ทธ๋ฆฌ๊ณ AvanteFactoryV2
๋ CarFactory
๋ฅผ ๊ตฌํํ๋๋ฐ createCar
๋ง ๊ตฌํํด์ฃผ๋ฉด ๋๋ค. ๋ฌผ๋ก ์ฌ๊ธฐ์๋ AvanteV2๋ฅผ ๋ฐํ์ํค๋ฉด ๋๊ธฐ ๋๋ฌธ์ ์ฝ๋๋ฅผ ํฌ๊ฒ ์์ฑํ ํ์๋ ์๋ค.
public class Client {
public static void main(String[] args) {
Car car1 = new AvanteFactoryV2().orderCar("์ต์คํธ", "white");
System.out.println(car1.toString());
}
}
๊ทธ๋ผ ์ค์ ๋ก orderCar()
mehtod๋ฅผ ํตํด ์คํ์ ํด๋ณด๋ฉด
์ด์ ๊ณผ ๋์ผํ๊ฒ ์์ฐ์ ํด๋ผ ์ ์๋ค๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๊ทธ๋ผ ์ด์ ์ด ์ฝ๋๊ฐ ์ง์ง๋ก OCP๋ฅผ ์งํฌ ์ ์์๊ฒ์ธ๊ฐ? GV80์ ์์ฐํด๋ด๋ฉฐ ํ์ธํด๋ณด์!
public class GV80V2 extends Car {
public GV80V2() {
setName("GV80");
setEngine("v2+");
setLogo("์ ๋ค์์ค");
}
}
public class GV80FactoryV2 implements CarFactory{
@Override
public Car createCar() {
return new GV80V2();
}
}
์ฌ๊ธฐ์ ํจํด์ ํ์ ๋๋ ์ ์์๋๋ฐ. ๊ทธ ์ด๋ค ์ฝ๋์ ์์ ๋ ์์ด GV80V2
GV80FactoryV2
๋๊ฐ์ class๋ง ์ถ๊ฐํ๋ ๊ฒ์ผ๋ก ์ฐจ๋ ์์ฐ ์ฝ๋๊ฐ ๋๋ฌ๋ค.
์ด๋ฅผ ํตํด ์ฐ๋ฆฌ๋ OCP๋ฅผ ์ ์งํจ ์ฝ๋๋ฅผ ์์ฐํด๋๋ค๊ณ ์๊ฐํ ์ ์๋ค.
public class Client {
public static void main(String[] args) {
Car car1 = new AvanteFactoryV2().orderCar("์ต์คํธ", "white");
Car car2 = new GV80FactoryV2().orderCar("์ต์คํธ", "white");
System.out.println(car1.toString());
System.out.println(car2.toString());
}
}
์ด๋ฒ์ ๋ ์ฐจ๋์ ๋์์ ์์ฐํด๋ณด๋ฉด
๊ฐ์ฅ ์ฒ์์ ๋ฌด์ํ๊ฒ ์์ฑํ ์ฝ๋์ ๋์ผํ ๊ธฐ๋ฅ์ ์ ์คํํด์ฃผ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
ํ์ง๋ง ์ด ์ฝ๋์์๋ ๋ฌธ์ ์ ์ด ์๋๋ฐ ์ฐจ๋ ์์ฐ์ ์์ฒญํ๋ Client ์ฝ๋์์ ๊ฐ๊ฐ์ Factory๋ฅผ ์ง์ ์ง์ ํด์ฃผ์ด์ผ ํ๋ค๋ ์ ์ด๋ค.
public class Client {
public static void main(String[] args) {
order(new AvanteFactoryV2(), "์ต์คํธ", "white");
order(new GV80FactoryV2(), "์ต์คํธ", "black");
}
private static void order(CarFactory carFactory, String owner, String color){
Car car = carFactory.orderCar(owner, color);
System.out.println(car.toString());
}
}
Client์ ์ฝ๋๊น์ง ๋ค์๊ณผ ๊ฐ์ด ์์ ํ๊ฒ ๋๋ฉด ์ค๋ณต๋๋ ์ฝ๋๋ฅผ ์์ฐ๊ณผ ๋์์ main์์๋ order์ ๋ง๋ factory์ ๊ตฌ๋งค์ ์ ๋ณด๋ง ๋๊ฒจ์ฃผ๋ฉด ๋๋ ์ฝ๋๋ก ๋ฆฌํฉํ ๋ง ๋๋ค.
public class Car {
private String owner;
private String name;
private String color;
private String logo;
private String engine;
private String navi;
...
}
๊ธฐ๋ณธ ๊ตฌ์กฐ๊ฐ ๋๋ Car
class์ navi๋ฅผ ์ถ๊ฐํด์ค๋ค.
public interface CarFactory {
...
private void settingCar(Car car, String owner, String color){
car.setOwner(owner);
car.setColor(color);
car.setNavi("Kakao Navi");
}
}
๊ทธ ํ์ ๋๋ settingCar()
method์ navi๋ฅผ ์ธํ
ํ ์ ์๋๋ก ์์ ํ๋ค.
๊ทธ๋ผ ๊ฒฐ๊ณผ๋ก ๋ชจ๋ ์ฐจ๋์ navigation์ด ์ถ๊ฐ๋๊ฒ์ ํ์ธํด๋ณผ ์ ์๋ค!
์ด๋ ๊ฒ ์ถ๊ฐ์ ์ธ ์ฌํญ์ด ์๊ฒจ๋ ๋์์ธ ํจํด์ ์ ์ฉํด๋๋ ์ฝ๋์ ์์ ์ด ๋๋ฌด ํธํด์ง๊ฒ์ด๋ค.
์ฅ์
OCP๋ฅผ ์งํค๋ ์ฝ๋๋ฅผ ์์ฐํด๋ผ ์ ์๋ค. ๋ํ factory์ product๊ฐ์ ๋์จํ ๊ฒฐํฉ์ ์ ์งํ ์ ์๋ค.
๋จ์
ํ์ class๋ค์ ์๊ฐ ๋ง์์ ธ ๊ตฌ์กฐ๊ฐ ๋ณต์กํด์ง๋ค.
Open Closed Principle์ ์ค์๋ง๋ก ๋ณ๊ฒฝ์ ๋ซํ
์๊ณ ํ์ฅ์ ์ด๋ ค
์๋ค. ๋ผ๋ ์๋ฏธ์ด๋ค. ์ฐ๋ฆฌ๊ฐ ์ ์ฉํ ๋์์ธ ํจํด์์ ๋ณด๋ฉด GV80์ด๋ผ๋ ํ์ฅ์๋ ์ด๋ ค ์์ด ์ฝ๊ฒ ์ถ๊ฐ๊ฐ ๊ฐ๋ฅํ๋ค. ํ์ง๋ง ๊ธฐ์กด์ Avante๋ผ๋ ๊ธฐ๋ฅ์์๋ ์ ํ ์ฝ๋๊ฐ ์์ ๋๋ ๋ถ๋ถ์ด ์์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ์ผ๋ฏ๋ก ๋ณ๊ฒฝ์๋ ๋ซํ์๋ค๊ณ ๋ณผ ์ ์๋ค.
๊ธฐ์กด์ interface์์๋ ์ถ์ ๋ฉ์๋๋ง ์ ์๊ฐ ๊ฐ๋ฅํ์์ง๋ง, java8์์ Default method๊ฐ ์ถ๊ฐ๋์๊ณ java9์์๋ private method๊ฐ ์ถ๊ฐ๋์๋ค.
default method
๋ interface์์ ๋ฏธ๋ฆฌ method์ ๊ธฐ๋ฅ์ ์ ์ํด๋๊ณ ์์๋ฐ์ class์์๋ ๊ธฐ๋ฅ์ ๋์ผํ๊ฒ ์ฌ์ฉํ ์ ์๊ฒ๋ ๋ง์น extendํ๊ฒ๊ณผ ๋์ผํ๊ฒ ์๋ํ๋ค๊ณ ์๊ฐํ๋ฉด ์ฌ์ธ๊ฒ ๊ฐ๋ค.
private mehtod
๋ ๊ธฐ์กด interface๋ ๋ด๋ถ ๋ฉ์๋๋ฅผ ์ ์ํ ์ ์์์ง๋ง java9๋ถํฐ๋ ๋ด๋ถ ๋ฉ์๋๋ฅผ ์ ์ํ์ฌ default method์ ํจ๊ป ์ฌ์ฉํ ์ ์๊ฒ ๋ method์ด๋ค.