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;

    }

}

이러한 문제들을 해결해줄 구원자

builder

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. 옵셔널 데이터에 자유롭다

}