상세 컨텐츠

본문 제목

생성자를 팩토리 메서드로 치환 (Replace Constructor with Factory Method )

자바강좌/리팩토링

by somiyuralove 2020. 2. 10. 22:05

본문

* 생성자를 팩토리 메서드로 치환 (Replace Constructor with Factory Method )
- 생성하고 싶은 인스턴스가 속한 실제 클래스를 클라이언트에서는 숨기고 싶음.
- 생성자를 팩토리 메서드로 치환함.
- 어느 클래스 인스턴스를 생성할지를 팩토리 메서드 안에서 정할 수 있음
- 생성한 인스턴스를 변경해도 클라이언트 쪽은 변경하지 않아도 됨.
- 추상도가 너무 올라가면 코드가 오히려 난해해짐.

* 방법
1. 팩토리 메서드 작성
1) 팩토리 메서드 작성 - 팩토리 메서드 안에서는 현재 생성자를 호출
2) 팩토리 메서드 호출 - 클라이언트에서 생성자를 호출하는 부분을 수정해서 팩토리 메서드를 호출하도록 함
3) 컴파일해서 테스트
2. 생성자 숨기기
1) 생성자를 private로 만듬 - 그러면 생성자를 클라이언트에서 실수로 호출하는 걸 막을 수 있어서 팩토리 메서드 호출이 보장됨.
2) 컴파일


* 리팩토링 전 코드

package ReplaceConstructorWithFactoryMethod.before;

public class Shape {
public static final int TYPECODE_LINE = 0;
public static final int TYPECODE_RECTANGLE = 1;
public static final int TYPECODE_OVAL = 2;

private final int _typecode;
private final int _startx;
private final int _starty;
private final int _endx;
private final int _endy;

public Shape(int typecode, int startx, int starty, int endx, int endy) {
_typecode = typecode;
_startx = startx;
_starty = starty;
_endx = endx;
_endy = endy;
}

public int getTypecode() {
return _typecode;
}

public String getName() {
switch (_typecode) {
case TYPECODE_LINE:
return "LINE";
case TYPECODE_RECTANGLE:
return "RECTANGLE";
case TYPECODE_OVAL:
return "OVAL";
default:
return null;
}

}

public String toString() {
return "[ "
+ getName() + ", "
+ "(" + _startx + ", " + _starty + ")-"
+ "(" + _endx + ", " + _endy + ") ]";
}

public void draw() {
switch(_typecode) {
case TYPECODE_LINE:
drawLine();
break;
case TYPECODE_RECTANGLE:
drawRectangle();
break;
case TYPECODE_OVAL:
drawOval();
break;
}
}

private void drawLine() {
System.out.println("drawLine: " + this.toString());
}

private void drawRectangle() {
System.out.println("drawRectangle: " + this.toString());
}

private void drawOval() {
System.out.println("drawOval: " + this.toString());
}
}


package ReplaceConstructorWithFactoryMethod.before;

public class Main {
public static void main(String[] args) {
Shape line = new Shape(Shape.TYPECODE_LINE, 0, 0, 100, 200);
Shape rectangle = new Shape(Shape.TYPECODE_RECTANGLE, 10, 20, 30, 40);
Shape oval = new Shape(Shape.TYPECODE_OVAL, 100, 200, 300, 400);

Shape[] shape = {
line,
rectangle,
oval,
};

for(Shape s : shape) {
s.draw();
}
}
}

* 리팩토링 후 코드

package ReplaceConstructorWithFactoryMethod.after;

public class Shape {
public static final int TYPECODE_LINE = 0;
public static final int TYPECODE_RECTANGLE = 1;
public static final int TYPECODE_OVAL = 2;

private final int _typecode;
private final int _startx;
private final int _starty;
private final int _endx;
private final int _endy;

public static Shape create(int typecode, int startx, int starty, int endx, int endy) {
return new Shape(typecode, startx, starty, endx, endy);
}

private Shape(int typecode, int startx, int starty, int endx, int endy) {
_typecode = typecode;
_startx = startx;
_starty = starty;
_endx = endx;
_endy = endy;
}

public int getTypecode() {
return _typecode;
}

public String getName() {
switch (_typecode) {
case TYPECODE_LINE:
return "LINE";
case TYPECODE_RECTANGLE:
return "RECTANGLE";
case TYPECODE_OVAL:
return "OVAL";
default:
return null;
}

}

public String toString() {
return "[ "
+ getName() + ", "
+ "(" + _startx + ", " + _starty + ")-"
+ "(" + _endx + ", " + _endy + ") ]";
}

public void draw() {
switch(_typecode) {
case TYPECODE_LINE:
drawLine();
break;
case TYPECODE_RECTANGLE:
drawRectangle();
break;
case TYPECODE_OVAL:
drawOval();
break;
}
}

private void drawLine() {
System.out.println("drawLine: " + this.toString());
}

private void drawRectangle() {
System.out.println("drawRectangle: " + this.toString());
}

private void drawOval() {
System.out.println("drawOval: " + this.toString());
}
}


package ReplaceConstructorWithFactoryMethod.after;

public class Main {
public static void main(String[] args) {
Shape line = Shape.create(Shape.TYPECODE_LINE, 0, 0, 100, 200);
Shape rectangle = Shape.create(Shape.TYPECODE_RECTANGLE, 10, 20, 30, 40);
Shape oval = Shape.create(Shape.TYPECODE_OVAL, 100, 200, 300, 400);

Shape[] shape = {
line,
rectangle,
oval,
};

for(Shape s : shape) {
s.draw();
}
}
}

* 리팩토링 한번 더 한 코드(분류 코드를 하위 클래스로 치환 )

package ReplaceConstructorWithFactoryMethod.subclass;

import ReplaceConstructorWithFactoryMethod.subclass.Shape;
import ReplaceConstructorWithFactoryMethod.subclass.ShapeLine;
import ReplaceConstructorWithFactoryMethod.subclass.ShapeOval;
import ReplaceConstructorWithFactoryMethod.subclass.ShapeRectangle;

public abstract class Shape {
public static final int TYPECODE_LINE = 0;
public static final int TYPECODE_RECTANGLE = 1;
public static final int TYPECODE_OVAL = 2;

private final int _startx;
private final int _starty;
private final int _endx;
private final int _endy;

public static Shape createLine(int startx, int starty, int endx, int endy) {
return new ShapeLine(startx, starty, endx, endy);
}

public static Shape createRectangle(int startx, int starty, int endx, int endy) {
return new ShapeRectangle(startx, starty, endx, endy);
}

public static Shape createOval(int startx, int starty, int endx, int endy) {
return new ShapeOval(startx, starty, endx, endy);
}

protected Shape(int startx, int starty, int endx, int endy) {
_startx = startx;
_starty = starty;
_endx = endx;
_endy = endy;
}


public String toString() {
return "[ "
+ getName() + ", "
+ "(" + _startx + ", " + _starty + ")-"
+ "(" + _endx + ", " + _endy + ") ]";
}

public abstract String getName();
public abstract void draw();
}


package ReplaceConstructorWithFactoryMethod.subclass;

import ReplaceConstructorWithFactoryMethod.subclass.Shape;

public class ShapeLine extends Shape{

public ShapeLine(int startx, int starty, int endx, int endy) {
super(startx, starty, endx, endy);
}
@Override public String getName() {
return "Line";
}
@Override public void draw() {
System.out.println("drawLine: " + this.toString());
}
}


package ReplaceConstructorWithFactoryMethod.subclass;

import ReplaceConstructorWithFactoryMethod.subclass.Shape;

public class ShapeOval extends Shape {

public ShapeOval(int startx, int starty, int endx, int endy) {
super(startx, starty, endx, endy);
// TODO Auto-generated constructor stub
}

@Override
public String getName() {
// TODO Auto-generated method stub
return "OVAL";
}

@Override
public void draw() {
// TODO Auto-generated method stub
System.out.println("drawOval: " + this.toString());
}

}

package ReplaceConstructorWithFactoryMethod.subclass;

import ReplaceConstructorWithFactoryMethod.subclass.Shape;

public class ShapeRectangle extends Shape{

public ShapeRectangle(int startx, int starty, int endx, int endy) {
super(startx, starty, endx, endy);
}

@Override
public String getName() {
// TODO Auto-generated method stub
return "RECTANGLE";
}

@Override
public void draw() {
// TODO Auto-generated method stub
System.out.println("drawRectangle: " + this.toString());
}

}


package ReplaceConstructorWithFactoryMethod.subclass;

public class Main {
public static void main(String[] args) {
Shape line = Shape.createLine(0, 0, 100, 200);
Shape rectangle = Shape.createRectangle(10, 20, 30, 40);
Shape oval = Shape.createOval(100, 200, 300, 400);

Shape[] shape = {
line,
rectangle,
oval,
};

for(Shape s : shape) {
s.draw();
}
}
}


관련글 더보기

댓글 영역