객체지향 이해하기
(내가 나를 가르치는 글이라 반말입니다)
자동차가 가진 속성이 뭘까? 색상, 브랜드, 제조일자, 몇인승, 튜닝여부, 현재 속도, 운전중/주차중, 키로 수, 연료량 등
행위는? 가속하기, 정지하기, 멈추기, 주유하기, 세차하기, 수리하기 등이 있을것이다
클래스로 만들어보자
public class Car {
private String name;
private int speed;
public Car(String name) {
this.name = name;
this.speed = 0;
}
public void accelerate() {
speed += 10;
System.out.println(name + " 차 가속! 속도: " + speed);
}
public void brakePedals() {
speed -= 10;
System.out.println(name + " 차 감속! 속도: " + speed);
}
}
클래스로 보면 이런 형태가 된다. 여기서 속성은 외부에서 변경할 수 없는 속성이고, 행위를 통해 속성을 변경할 수 있다.
=> 캡슐화
나는 전기차가 필요하다
public class ElectricCar extends Car {
private int battery;
public ElectricCar(String name) {
super(name);
this.battery = 100;
}
public void charge() {
this.battery = 100;
System.out.println("완충!");
}
}
자동차를 상속 받은 전기차는 자동자의 기본 기능을 그대로 사용할 수 있고, 전기차 만의 기능을 사용할 수 있다.
=> 상속
운전을 해보자
public class DriveCar {
public static void main(String[] args) {
Car myCar = new Car("부릉부릉");
Car myElecCar = new ElectricCar("찌릿찌릿");
myCar.accelerate();
myCar.stop();
myElecCar.accelerate(); // Car로 선언했지만 ElectricCar의 동작 가능 (다형성)
}
}
new ElectricCar();로 Car를 만들 수 있다. 마찬가지로 Car를 상속받은 어떠한 객체들도 동일하게 생성 할 수 있다.
=> 다형성
그냥 차도 좋아, 근데 모든 차는 에너지 보충이 필요하단 말이야
전기차는 전기 충전을 구현해야하고, 가솔린차는 가솔린 충전을 해줘야하는데 하나하나 넣는건 관리가 복잡하네
구현에 강제성을 줘서 협업과 유지보수를 편하게 하자
=> 상속 + 추상화
기존의 Car를 추상 클래스로 변경해보자
public abstract class AbstractCar {
protected String name;
protected int speed;
public AbstractCar(String name) {
this.name = name;
this.speed = 0;
}
public void accelerate() {
speed += 10;
System.out.println(name + " 차 가속! 속도: " + speed);
}
public void brakePedals() {
speed -= 10;
System.out.println(name + " 차 감속! 속도: " + speed);
}
public abstract void chargeEnergy(); // 상속받은 객체들의 공통, 각각 기능은 다를 수 있다.
}
전기차 다시 만들어야해
public class ElectricCar extends AbstractCar {
private int battery;
public ElectricCar(String name) {
super(name);
this.battery = 100;
}
@Override
public void chargeEnergy() {
battery = 100;
System.out.println(name + " 충전 완");
}
}
가솔린차도 만들자
public class GasolineCar extends AbstractCar {
private int fuel;
public GasolineCar(String name) {
super(name);
this.fuel = 100;
}
@Override
public void chargeEnergy() {
fuel = 100;
System.out.println(name + " 주유 완");
}
}
새차로 운전해보자
public class DriveCar {
public static void main(String[] args) {
AbstractCar gasCar = new Car("가스가스");
AbstractCar elecCar = new ElectricCar("찌릿찌릿");
gasCar.refuel();
gasCar.accelerate();
gasCar.stop();
elecCar.refuel();
elecCar.accelerate();
elecCar.stop();
}
}
refuel만으로 가솔린이 채워지는지 배터리가 채워지는지는 모르지만 행위로 여러 객체를 동일하게 다룰 수 있지
=> 다형성
만들다 보니 차말고, 배도 만들어야하네? 근데 배도 충전해야하잖아
AbstractCar를 쓰자고 할건 아니지? 충전이 필요한 객체의 추상은 아니잖아
이럴 땐 인터페이스를 쓰자
=> 추상화(+다형성)
public interface EnergyRechargeable {
void chargeEnergy(); // 에너지를 보충하는 기능
}
배도 만들고 차도 만들어보자
public class Ship implements EnergyRechargeable {
private String name;
private int fuel;
public Ship(String name) {
this.name = name;
this.fuel = 100;
}
@Override
public void chargeEnergy() {
fuel = 100;
System.out.println(name + " 주유 완");
}
}
public class GasolineCar implements EnergyRechargeable {
private String name;
private int fuel;
public GasolineCar(String name) {
this.name = name;
this.fuel = 100;
}
@Override
public void chargeEnergy() {
fuel = 100;
System.out.println(name + " 주유 완");
}
}
주유소에서 주유를!
public class RechargeStation {
public void recharge(EnergyRechargeable target) {
System.out.println("주유!");
target.chargeEnergy(); // 어떤 탈것이든 chargeEnergy만 있으면 동작 가능!
}
}
public class RechargeService {
public static void main(String[] args) {
EnergyRechargeable car = new ElectricCar("찌릿찌릿");
EnergyRechargeable ship = new Ship("통통통");
RechargeStation station = new RechargeStation();
station.recharge(car);
station.recharge(ship);
}
}
이제 상속과 추상화 다형성이 밀접하다는게 느껴지지?
위 코드들을 조합해서 다형성을 뽑아보자
EnergyRechargeable ship = new Ship("통통통통"); // 인터페이스 기반
AbstractCar car = new ElectricCar("찌릿짜릿"); // 추상 클래스 기반
ship.chargeEnergy();
car.chargeEnergy(); // 인터페이스, 추상 모두 다형성을 발생
아 무슨 또 비행기를 만드십니까?
이동 수단을 상속하고 에너지 충전은 인터페이스로 설계해서 Car, Ship, Plane을 구현해보자
EnergyRechargeable 는 그대로 쓸거야
public abstract class Vehicle {
protected String name;
protected int speed;
private String howToMove; // 어떻게 이동하는지
public Vehicle(String name, String howToMove) {
this.name = name;
this.speed = 0;
this.howToMove = howToMove;
}
public void accelerate() {
speed += 10;
System.out.println(name + " 가속! 속도: " + speed);
}
public void brake() {
speed -= 10;
System.out.println(name + " 감속! 속도: " + speed);
}
public String getHowToMove() {
return howToMove;
}
public abstract void move();
}
public class Car extends Vehicle implements EnergyRechargeable {
private int fuel;
public Car(String name) {
super(name, "도로를 달린다");
this.fuel = 100;
}
@Override
public void chargeEnergy() {
fuel = 100;
System.out.println(name + " 주유 완");
}
@Override
public void move() {
System.out.println(name + ": " + getHowToMove());
}
}
public class Plane extends Vehicle implements EnergyRechargeable {
private int fuel;
public Plane(String name) {
super(name, "하늘을 날아다닌다");
this.fuel = 100;
}
@Override
public void chargeEnergy() {
fuel = 100;
System.out.println(name + " 연료 충전 완");
}
@Override
public void move() {
System.out.println(name + ": " + getHowToMove());
}
}
달려라 달려
public class Drive {
public static void main(String[] args) {
Vehicle car = new Car("부릉부릉");
Vehicle plane = new Plane("슝슝슝슝");
Vehicle ship = new Ship("통통통통");
RechargeStation station = new RechargeStation();
station.recharge((EnergyRechargeable) car);
station.recharge((EnergyRechargeable) plane);
station.recharge((EnergyRechargeable) ship);
car.accelerate();
car.move(); // 출력: 부릉부릉: 도로를 달린다
plane.accelerate();
plane.move(); // 출력: 슝슝슝슝: 하늘을 날아다닌다
ship.accelerate();
ship.move(); // 출력: 통통통통: 바다 위를 떠다닌다
}
}
이런 구조를 가지면 Ship 클래스를 확인해보지 않아도 추론이 가능하다는 장점이 있어
객체지향은 단순한 문법이 아니라, 복잡한 문제를 유연하게 풀어내는 사고방식이야.
코드를 통해 현실 세계의 구조와 개념을 자연스럽게 녹여낼 수 있고,
캡슐화를 통해 데이터 보호와 제어가 가능하며, 상속은 공통 기능을 재사용하게 해줘.
추상화와 다형성은 변화에 강한 유연한 구조를 만들 수 있도록 도와주지.
결국 객체지향은 기능의 분리나 역할의 명확화를 넘어서,
유지보수와 확장성, 그리고 일관성 있는 협업 환경까지 만들어주는 강력한 개발 철학이기 때문에,
꼭 이해하고 체화할 필요가 있다고 생각해.
아니면 그냥 외워..!