정의

프로토타입 인스턴스를 사용하여 생성할 객체의 종류를 지정하고 이 프로토타입을 복사하여 새로운 객체를 생성

 

코드

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class PrototypeEx {

	static abstract class Shape implements Cloneable {
		public int x;
		public int y;
		public String color;

		public Shape() {}

		protected Shape(Shape target) {
			if (target != null) {
				this.x = target.x;
				this.y = target.y;
				this.color = target.color;
			}
		}

		public abstract Shape clone();

		@Override
		public boolean equals(Object object2) {
			if (!(object2 instanceof Shape))
				return false;
			Shape shape2 = (Shape) object2;
			return shape2.x == x && shape2.y == y && Objects.equals(shape2.color, color);
		}
	}

	static class Circle extends Shape {
		public int radius;

		public Circle() {
		}

		public Circle(Circle target) {
			super(target);
			if (target != null) {
				this.radius = target.radius;
			}
		}

		// 공변 반환타입
		@Override
		public Circle clone() {
			return new Circle(this);
		}

		@Override
		public boolean equals(Object object2) {
			if (!(object2 instanceof Circle) || !super.equals(object2))
				return false;
			Circle shape2 = (Circle) object2;
			return shape2.radius == radius;
		}
	}

	static class Rectangle extends Shape {
		public int width;
		public int height;

		public Rectangle() {
		}

		public Rectangle(Rectangle target) {
			super(target);
			if (target != null) {
				this.width = target.width;
				this.height = target.height;
			}
		}

		// 공변 반환타입
		@Override
		public Rectangle clone() {
			return new Rectangle(this);
		}

		@Override
		public boolean equals(Object object2) {
			if (!(object2 instanceof Rectangle) || !super.equals(object2))
				return false;
			Rectangle shape2 = (Rectangle) object2;
			return shape2.width == width && shape2.height == height;
		}
	}

	public static void main(String[] args) {
		List<Shape> shapes = new ArrayList<>();
		List<Shape> shapesCopy = new ArrayList<>();

		Circle circle = new Circle();
		circle.x = 10;
		circle.y = 20;
		circle.radius = 15;
		circle.color = "red";

		Circle circle2 = circle.clone();
		circle2.x = 11;

		// 1
		shapes.add(circle);
		shapesCopy.add(circle);
		// 2
		shapes.add(circle);
		shapesCopy.add(circle2);

		Rectangle rectangle = new Rectangle();
		rectangle.width = 10;
		rectangle.height = 20;
		rectangle.color = "blue";

		Rectangle rectangle2 = rectangle.clone();
		// 3
		shapes.add(rectangle);
		shapesCopy.add(rectangle2);

		cloneAndCompare(shapes, shapesCopy);
	}

	private static void cloneAndCompare(List<Shape> shapes, List<Shape> shapesCopy) {

		for (int i = 0; i < shapes.size(); i++) {
			if (shapes.get(i) != shapesCopy.get(i)) {
//            	System.out.println(System.identityHashCode(shapes.get(i))+" "+System.identityHashCode(shapesCopy.get(i)));
				System.out.print(i + ": 도형이 서로 다른 객체입니다.");
				if (shapes.get(i).equals(shapesCopy.get(i))) {
					System.out.println(i + ": 그리고 같은 값을 가집니다.");
				} else {
					System.out.println(i + ": 그리고 다른 값입니다.");
				}
			} else {
				System.out.println(i + ": 도형이 서로 같은 객체입니다.");
			}
		}
	}
}

결과

0: 도형이 서로 같은 객체입니다.
1: 도형이 서로 다른 객체입니다.1: 그리고 다른 값입니다.
2: 도형이 서로 다른 객체입니다.2: 그리고 같은 값을 가집니다.

 

예시로만 알아두고, 실제 "Cloneable"는 제한적으로 사용해야 한다.

예시는 슈퍼클래스가 abstract라 사용했다. 

이펙티브 자바에 아이템 13 부분에선 Cloneable 대신 복사 생성자나 복사 팩터리를 사용하라 권고한다.(배열은 제외)

위 예시에서 복사 생성자를 사용했다.

 

+ Recent posts