class Robot {
private String name;
private int power;
private int energy;
// 2. 그래서 필요한게 풀생성자
public Robot(String name, int power, int energy) {
this.name = name;
this.power = power;
this.energy = energy;
}
}
public class Test {
// 1. 객체 지향에서 가장 중요한 것은.. 객체를 생성할 때
//Robot r = new Robot(); // 이렇게 만들면 안됨. 기존 값을 꼭 초기화를 해줘야함
Robot robot = new Robot("휴고", 1000, 100);
}
// 2. 옵셔널 데이터 처리?를 위해 보통 이렇게함
// **추상클래스**를 만든다
abstract class AttackRobot { // 4. 얘를 인터페이스로 만들 순 없음. 그러면 변수가 static 이 됨
private String attackType;
public AttackRobot(String attackType) {
this.attackType = attackType;
}
}
abstract class GeneralRobot {
}
// 3. 옵셔널 데이터를 쓰는게 아니라, 클래스를 상속함
class Robot extends AttackRobot{
private String name;
private int power;
private int energy;
//private String attackType; // 옵셔널 데이터
// 1. 옵셔널 데이터란? 어떤 로봇은 공격을 하고, 어떤 로봇은 공격을 아예 안해!
// 5. AttackRobot 의 변수도 추가되어야함
public Robot(String name, int power, int energy, String attackType) {
super(attackType); // 5-1. 부모의 변수를 담기
this.name = name;
this.power = power;
this.energy = energy;
}
}
// 6. 다른 로봇을 만들기 위해 클래스를 하나 더 생성
// 로봇의 종류가 다 다르게 되면 클래스를 계속 만들어야한다는 단점이 있음
class AnotherRobot extends GeneralRobot{
private String name;
private int power;
private int energy;
public AnotherRobot(String name, int power, int energy) {
this.name = name;
this.power = power;
this.energy = energy;
}
}
// 3. String 이 아닌 얘를 따로 클래스로 뺌
class Attack {
}
// 1. 다시 이게 더 낫지않을까..?
class Robot {
private String name;
private int power;
private int energy;
private Attack attackType; // 컴포지션
// 2. 데이터가 만약 이렇게 들어와야 한다면
// 물리공격(칼, 근접공격,..) 마법공격
// 컴포지션 기법을 쓰는 경우에는, 옵셔널이 되는 경우가 많음.
// 추상클래스 기법과 다름. 추상클래스는 옵셔널이 되는 경우가 없음.
// 3. 따라서 생성자를 두개를 만들어야함 -> 옵셔널이니까
public Robot(String name, int power, int energy, Attack attackType) {
this.name = name;
this.power = power;
this.energy = energy;
this.attackType = attackType;
}
// 4. 컴포지션의 종류가 많아지면 마찬가지로 생성자의 갯수가 무지막지하게 늘어남
// 생성자 오버로딩 많아짐 -> 사용자가 사용하기에 어려움
public Robot(String name, int power, int energy) {
this.name = name;
this.power = power;
this.energy = energy;
}
}
이러한 문제들을 해결해줄 구원자
class Attack {
}
// builder
class Robot {
private String name;
private int power;
private int energy;
private Attack attackType;
// 강제로 new 못하게 막아버림
private Robot() {
}
public static Robot builder(){
return new Robot();
}
public Robot(String name, int power, int energy, Attack attackType) {
this.name = name;
this.power = power;
this.energy = energy;
this.attackType = attackType;
}
// setter 함수의 형태를 띄고 있음
// 리턴 타입이 자기자신
public Robot name(String name){
this.name = name;
return this;
}
public Robot power(int power){
this.power = power;
return this;
}
public Robot energy(int energy){
this.energy = energy;
return this;
}
public Robot attackType(Attack attackType){
this.attackType = attackType;
return this;
}
}
public class Test {
Robot r = Robot.builder()
.name("휴고")
.power(1000)
.energy(100); // 옵셔널이니까 attack 안넣어도 됨
// 빌더의 장점
// 1. 실수할 일이 없다 -> 생성자에는 순서가 있음
// 2. 옵셔널 데이터에 자유롭다
}