본문 바로가기

코딩/Software Architecture

[GoF Design Pattern] Prototype

*Prototype Pattern

Prototype : 실행 중에 생성된 객체로 다른 객체를 생성하는 패턴. 'new class' 사용해 생성하는 게 아니고 이미 생성된 객체를 통해 독립된 또 다른 객체를 생성함. 

Prototype으로 만든 객체의 상태를 변경해도 원본 객체의 상태는 변경되지 않음.

Prototype: 객체로부터 또 다른 새로운 객체를 생성하는 API 가지고 있음

Shape : 도형에 대한 API

Point, Line, Grpup : 도형을 구체적으로 구현, Prototype, Shape를 구현.

Group : Shape 인터페이스와 호환되는 여러 개의 객체를 이용해 새로운 도형을 생성 가능.

 

public interface Prototype {
	Object copy();
}
public interface Shape {
    String draw(); // 도형을 표현하는 문자열을 반환하는 매서드
    void moveOffset(int dx, int dy); // 도형을 이동하는 메서드
}
public class Point implement Shape, Prototype {
    private int x;
    private int y;
    
    public Point setX(int x) {
    	this.x = x;
        return this;
    }
    
    public Point setY(int y) {
    	this.y = y;
        return this;
    }
    
    public int getX() {
    	return x;
    }
    
    public int getY() {
    	return y;
    }
    
    
    @Override
    public Object copy() {
    	Point newPoint = new Point();
        
        newPoint.x = this.x;
        newPoint.y = this.y;
        
        return newPoint;
    }
    
    @Override
    public String draw() {
    	return "(" + x + " " + y + ")";
    
    }
    
    @Override
    public void moveOffset(int dx, int dy) {
    	this.x += dx;
        this.y += dy;
    }
}
public class Line implements Shape, Prototype {
    private Point startPt;
    private Point endPt;
    
    public Line setStartPoint(Point pt) {
    	this.startPt = pt;
        return this;
    }
    
    public Line setEndPoint(Point pt) {
    	this.endtPt = pt;
        return this;
    }
    
    public Point getStartPoint() {
    	return startPt;
    }
    
    public Point getEndPoint() {
    	return endPt;
    }

    @Override
    public Object copy() {
    	Line newLine = newLine();
        
        newLine.startPt = (Point)startPt.copy();
        newLine.endPt = (Point)endPt.copy();
        
        return newLine;
    }
    
    @Override
    public String draw() {
    	return "LINE(" + startPt.draw() + "," + endPt.draw() + ")";
    
    }
    
    @Override
    public void moveOffset(int dx, int dy) {
    	startPt.moveOffset(dx, dy);
        endPt.moveOffset(dx, dy);
    
    }
    
}
public class Group implements Shape, Prototype {

    private ArrayList<Shape> shapeList = new ArrayList<>();
    
    private String name;
    
    public Group(String name) {
    	this.name = name;
    }
    
    Group addShape(Shape shape) {
    	shapeList.add(shape);
        return this;
    }
    
        @Override
    public Object copy() {
    	Group newGroup = new Group(name);
        
        Iterator<Shape> iter = shapeList.iterator();
            while(iter.hasNext()) {
                Prototype shape = (Prototype)iter.next();
                newGroup.shapeList.add((Shape)shape.copy());
        }
        return newGroup;
    }
    
    @Override
    public String draw() {
    	StringBuffer result = new StringBuffer(name);
        result.append("(");
        
        Iterator<Shape> iter = shapeList.iterator();
        while(iter.hasNext()) {
            Shape shape = iter.next();
            result.append(shape.draw());
            if(iter.hasNext()) {
            	result.append(" ");
            }
        }
        
        result.append(")");
        return result.toString();
    }
    
    @Override
    public void moveOffset(int dx, int dy) {
        Iterator<Shape> iter = shapeList.iterator();
        while(iter.hasNext()) {
            Shape shape = iter.next();
            shape.moveOffset(dx, dy);
        }
    }
}

 

실행 중 만든 객체를 통해 새로운 객체를 생성하는 패턴

이때 원본의 객체와 복사본의 객체는 완전 독립이어서 서로 영향을 주지 않음.

기존의 클래스를 조합해 새로운 개념의 객체를 생성하는 상황에서 Prototype 패턴을 적용하면 좋다.

public static void main(String[] args) {
    Point pt1 = new Point();
    pt1.setX(0).setY(0);
    
    Point pt2 = new Point();
    pt2.setX(100).setY(0);
    
    Lint line1 = new Line();
    line1.setStartPoint(pt1).setEndPoint(pt2);
    
    Line lineCopy = (Line)line1.copy();
    
    Point pt3 = new Point();
    pt3.setX(100).setY(100);
    
    Point pt4 = new Point();
    pt4.setX(0).setY(100);
    
    Line line2 = new Line();
    line2.setStartPoint(pt2).setEndPoint(pt3);
    
    Line line3 = new Line();
    line3.setStartPoint(pt3).setEndPoint(pt4);
    
    Line line4 = new Line();
    line4.setStartPoint(pt4).setEndPoint(pt1);
    
    Group rect = new Group("RECT");
    rect.addShape(line1).addShape(line2).addShape(line3).addShape(line4);
    System.out.println(rect.draw());
    
    Group cloneRect = (Group)rect.copy();
    cloneRect.moveOffset(100,100);
}