프로토타입 기반 언어는 클래스의 개념 없이 객체를 중심으로 동작하는 객체 지향 프로그래밍 언어를 의미. 객체 생성과 상속의 개념이 클래스가 아닌 프로토타입을 기반으로 이루어짐.
객체를 동적으로 수정하고 확장 가능하며, 클래스 정의가 필요 없기에 코드가 간단하다. 또한 기존 객체를 복사하여 새로운 객체를 쉽게 생성이 가능하다.
하지만, 프로토타입 체인이 깊어질 수록 디버깅이나 유지보수가 어려워질 수 있으며 클래스 기반이 아니기에 구조적 규칙이 약해 코드의 일관성이 떨어질 수 있다. 또한 런타임 시 동적인 속성 추가나 상속이 이루어지기 때문에 성능에 문제가 될 수 있다.
ex) JavaScript : 가장 대표적인 프로토타입 기반 언어
// 프로토타입 객체 생성
const animal = {
sound: function() {
console.log(this.noise);
}
};
// animal을 프로토타입으로 하는 객체 생성
const dog = Object.create(animal);
dog.noise = "Bark!";
dog.sound(); // 출력: "Bark!"
// animal을 프로토타입으로 하는 또 다른 객체 생성
const cat = Object.create(animal);
cat.noise = "Meow!";
cat.sound(); // 출력: "Meow!"
Java Spring/Spring Boot와 관련하여 프로토타입 기반 언어의 개념을 이해하거나 응용할 실습은 직접적인 연관이 적지만, 이 개념을 활용하여 Java에서 객체 지향의 동작 방식과 비교하거나 유연한 객체 생성 및 처리를 연습하는 데 도움이 될 수 있습니다. 특히 백엔드 개발자로서 객체 생성 및 의존성 주입을 이해하는 데 응용할 수 있습니다.
다음은 신입 백엔드 개발자로서 실습 가능한 방향과 아이디어입니다.
Spring은 객체 생성을 관리하는 빈 스코프(Bean Scope)로 프로토타입(prototype) 스코프를 제공합니다. 이를 활용해 객체의 유연한 생성과 관리를 실습할 수 있습니다.
@Scope("prototype")과 @Scope("singleton")을 설정하고, 빈의 생성 및 사용 방식을 비교합니다.@Component
@Scope("prototype")
public class PrototypeBean {
public PrototypeBean() {
System.out.println("Prototype Bean 생성");
}
}
@Component
@Scope("singleton")
public class SingletonBean {
public SingletonBean() {
System.out.println("Singleton Bean 생성");
}
}
@RestController
public class ScopeController {
private final PrototypeBean prototypeBean;
private final SingletonBean singletonBean;
public ScopeController(PrototypeBean prototypeBean, SingletonBean singletonBean) {
this.prototypeBean = prototypeBean;
this.singletonBean = singletonBean;
}
@GetMapping("/scope")
public String testScope() {
System.out.println("Prototype Bean: " + prototypeBean);
System.out.println("Singleton Bean: " + singletonBean);
return "Check console for results!";
}
}
Java에서는 프로토타입 기반 객체 생성을 구현하기 위해 Prototype Design Pattern을 사용할 수 있습니다. 이를 통해 객체를 동적으로 복제(clone)하는 방법을 익히고 Spring의 프로토타입 스코프와 비교할 수 있습니다.
class Animal implements Cloneable {
String name;
public Animal(String name) {
this.name = name;
}
@Override
public Animal clone() throws CloneNotSupportedException {
return (Animal) super.clone();
}
}
public class PrototypeExample {
public static void main(String[] args) throws CloneNotSupportedException {
Animal dog = new Animal("Dog");
Animal clonedDog = dog.clone();
System.out.println("Original: " + dog.name);
System.out.println("Cloned: " + clonedDog.name);
}
}
@Scope("prototype")과 결합해 비교하면, 직접적으로 객체를 복제하는 방식과 Spring Container가 관리하는 객체 생성 방식의 차이를 이해할 수 있습니다. Spring에서는 동적으로 필요한 객체를 생성하거나 프로토타입 스코프의 객체를 주입하기 위해 ObjectProvider를 사용합니다. 이를 실습해보면 객체 생성을 유연하게 처리하는 방법을 익힐 수 있습니다.
ObjectProvider를 사용해 프로토타입 객체 동적 생성@Component
@Scope("prototype")
public class DynamicBean {
public DynamicBean() {
System.out.println("Dynamic Bean 생성");
}
}
@RestController
public class DynamicController {
private final ObjectProvider<DynamicBean> dynamicBeanProvider;
public DynamicController(ObjectProvider<DynamicBean> dynamicBeanProvider) {
this.dynamicBeanProvider = dynamicBeanProvider;
}
@GetMapping("/dynamic")
public String createDynamicBean() {
DynamicBean bean = dynamicBeanProvider.getObject();
System.out.println("사용 중인 Bean: " + bean);
return "Dynamic Bean 생성 완료!";
}
}
/dynamic 엔드포인트를 호출할 때마다 새로운 객체가 생성됨을 확인할 수 있습니다.백엔드 개발자로서 객체 관리 및 생성을 API로 설계해보는 것도 실습이 될 수 있습니다.
@RestController
@RequestMapping("/api/objects")
public class ObjectController {
private final List<Map<String, Object>> objects = new ArrayList<>();
@PostMapping
public Map<String, Object> createObject(@RequestBody Map<String, Object> data) {
objects.add(data);
return data;
}
@GetMapping
public List<Map<String, Object>> getObjects() {
return objects;
}
}
/api/objects로 JSON 데이터를 보내 객체 생성/api/objects로 현재 저장된 객체 리스트 확인프로토타입 기반 객체 생성은 플러그인 시스템 설계에 적합합니다. 동적으로 새로운 기능을 추가하거나 변경할 수 있는 구조를 만들어보세요.
이와 같은 실습을 통해 Spring/Spring Boot의 실제 동작 원리와 객체 관리를 이해하고, 유연한 설계 방식을 학습할 수 있습니다.