
객체를 왜 사용하는가?
- 코드복잡성 하락, 유지보수성 상승, 재사용성 상승
객체지향적 코드
// 자동차 계기판의 정보를 관리하는 클래스
class Dashboard {
private int speed; //속도
private int fuelLevel; //연료
public Dashboard() {
this.speed = 0; // 초기 속도는 0
this.fuelLevel = 100; // 초기 연료는 100
}
// 속도를 설정하는 메서드
public void setSpeed(int speed) {
this.speed = speed;
}
// 연료량을 설정하는 메서드
public void consumeFuel(int amount) {
if (this.fuelLevel - amount >= 0) {
this.fuelLevel -= amount;
} else {
this.fuelLevel = 0;
}
}
// 계기판 정보를 출력하는 메서드
public void displayDashboard() {
System.out.println("Speed: " + this.speed + " km/h");
System.out.println("Fuel Level: " + this.fuelLevel + " %");
}
}
class Car {
private String model;
private String color;
private Dashboard dashboard; // 계기판 객체 포함
public Car(String model, String color) {
this.model = model;
this.color = color;
this.dashboard = new Dashboard(); // 새로운 계기판 생성
}
// 속도를 올리는 메서드
public void accelerate(int increment) {
this.dashboard.setSpeed(this.dashboard.speed + increment); // 속도 증가
this.dashboard.consumeFuel(5); // 가속할 때마다 연료 5 소비
}
// 현재 자동차 상태를 계기판으로 출력하는 메서드
public void displayStatus() {
System.out.println("Model: " + this.model + ", Color: " + this.color);
dashboard.displayDashboard(); // 계기판 정보 출력
}
}
public class Main {
public static void main(String[] args) {
Car car1 = new Car("Tesla", "Red");
Car car2 = new Car("BMW", "Blue");
// Tesla 가속
car1.accelerate(60);
car1.displayStatus(); // Tesla의 상태 출력
// BMW 가속
car2.accelerate(30);
car2.displayStatus(); // BMW의 상태 출력
}
}
- car class 와 dashboard class의 분리로 객체별 책임을 분리 유지보수성이 높아진다.
- 하나 class의 기능이 추가되거나 변경되도 영향이 가지않는다.
- 모든객체를 수정할 필요성이 없어짐.
절차적 코드
public class Main {
// 자동차의 상태를 저장하는 변수들
static String car1Model = "Tesla";
static String car1Color = "Red";
static int car1Speed = 0;
static int car1FuelLevel = 100;
static String car2Model = "BMW";
static String car2Color = "Blue";
static int car2Speed = 0;
static int car2FuelLevel = 100;
// 자동차의 속도를 증가시키는 함수
public static void accelerate(int increment, String model) {
if (model.equals(car1Model)) {
car1Speed += increment;
car1FuelLevel -= 5;
} else if (model.equals(car2Model)) {
car2Speed += increment;
car2FuelLevel -= 5;
}
}
// 계기판 상태를 출력하는 함수
public static void displayDashboard(String model) {
if (model.equals(car1Model)) {
System.out.println("Model: " + car1Model + ", Color: " + car1Color);
System.out.println("Speed: " + car1Speed + " km/h");
System.out.println("Fuel Level: " + car1FuelLevel + " %");
} else if (model.equals(car2Model)) {
System.out.println("Model: " + car2Model + ", Color: " + car2Color);
System.out.println("Speed: " + car2Speed + " km/h");
System.out.println("Fuel Level: " + car2FuelLevel + " %");
}
}
public static void main(String[] args) {
// Tesla 가속
accelerate(60, car1Model);
displayDashboard(car1Model);
// BMW 가속
accelerate(30, car2Model);
displayDashboard(car2Model);
}
}
- 자동차별 변수네임을 통해서 필드를 관리해야함.
- 중복코드들이 발생, 유지보수성싱 낮다.
차이점

- Class 하나의 책임을 많이 주면 의존성이 너무 높아지고 확장성이 낮아진다.
- 책임의 분리로 인한 기능의 독립성이 올라간다.
- 하나의 클래스로 여러 객체를 만들어 동일하게 사용이 가능.
(기능의 추가와 변경을 Class 로만 변경가능)
- 객체에 대한 책임분리는 기준과 기획서의 따라 달라짐
- 너무 상세하게 쪼갤시 유지보수와 협업에서의 관점에서 불리
객체의특징 4가지
캡슐화

class Car {
private String model; // 외부에서 접근할 수 없음
private int fuelLevel; // 외부에서 접근할 수 없음
private int speed;
// 생성자
public Car(String model) {
this.model = model;
this.speed = 0; // 기본 속도는 0
}
// 외부에서 속도를 변경할 수 있는 메서드 제공
public void accelerate(int increment) {
if (increment > 0) {
this.speed += increment;
}
}
// 현재 속도를 반환하는 메서드
public int getSpeed() {
return this.speed;
}
}
- 객체의 필드와 메서드를 하나의 단위를 묶고, 외부에서 직접접근을 막음. (접근 제어자)
- 원하는 필드, 메서드만 외부로 열어줄수 있음.
상속

class Car {
private int speed;
private int fuelLevel;
public Car() {
this.speed = 0;
this.fuelLevel = 100;
}
public void accelerate(int increment) {
this.speed += increment;
this.fuelLevel -= 5;
}
public void displayStatus() {
System.out.println("Speed: " + speed + " km/h");
System.out.println("Fuel Level: " + fuelLevel + " %");
}
}
// Tesla는 Car 클래스를 상속받음
class Tesla extends Car {
private boolean autonomousDrivingMode;
@Override
public void accelerate(int increment) {
super.accelerate(increment * 2); // Tesla는 속도가 두 배로 증가
}
public void setAutonomousDrivingMode() {
this.autonomousDrivingMode = true
}
//...
}
- 부모클래스의 멤버를 자식클래스가 상속받아서 사용하고 필요시 기능을 추가하거나 재정의 가능 (@Override).
- 상속이 없었다면 자동차 객체마다 계속 코드를 작성해야함.
추상화

abstract class Car {
protected int speed;
protected int fuelLevel;
public Car() {
this.speed = 0;
this.fuelLevel = 100;
}
// 추상 메서드: 각 자동차마다 가속 방식이 다를 수 있음
public abstract void accelerate();
public void displayStatus() {
System.out.println("Speed: " + speed + " km/h");
System.out.println("Fuel Level: " + fuelLevel + " %");
}
}
class Tesla extends Car {
@Override
public void accelerate() {
speed += 60; // Tesla는 60씩 가속
fuelLevel -= 5;
}
}
class BMW extends Car {
@Override
public void accelerate() {
speed += 30; // BMW는 30씩 가속
fuelLevel -= 5;
}
}
- Java에서는
abstract or interface 키워드를 활용하여 추상화
- 복잡한 내부로직을 감추고 상위클래스에서 필요한 부분만 외부에 노출함.
- 구현클래스들이 필요한부분을 추가적으로 구현.
- 구조적인 부분만 정의를 하고 하위클래스에게 구현을 하게 만들수있음
(Interface의 경우 구현의 강제성을 띄기에 무조건 구현해야함)
다형성

public class Main {
public static void main(String[] args) {
Car tesla = new Tesla(); // Car 타입으로 Tesla 객체 생성
Car bmw = new BMW(); // Car 타입으로 BMW 객체 생성
tesla.accelerate(); // Tesla의 accelerate() 호출
bmw.accelerate(); // BMW의 accelerate() 호출
tesla.displayStatus();
bmw.displayStatus();
}
}
- 메서드 행위자체가 동일할때 객체가 호출시 결과가 달라지는 현상.
- 일관된 인터페이스로 다양한 객체를 제어할 수 있다.
- 다형성을 사용하면 하나의 명령어를 다양한 방식으로 처리할 수 있어, 코드의 유연성과 확장성을 극대화
- 새로운 기능을 추가하거나 변경할 때도 간단히 확장할 수 있어 유지보수에 유리하며, 코드를 보다 효율적으로 관리