상속, 다형성, 캡슐화, 추상화의 실전 활용

 

객체지향 프로그래밍(OOP)의 네 가지 핵심 원칙인 상속, 다형성, 캡슐화, 추상화는 효율적이고 유지보수 가능한 코드를 작성하는 데 필수적인 개념입니다.

이 글에서는 각 원칙의 실전 활용 방법을 살펴보겠습니다.

상속(Inheritance)의 실전 활용

상속은 기존 클래스의 속성과 메서드를 새 클래스가 물려받는 메커니즘입니다. 이를 통해 코드 재사용성을 높이고 계층적 관계를 구현할 수 있습니다.

 

실제 예제: 차량 관리 시스템

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 부모 클래스
class Vehicle {
    protected String modelName;
    protected String brand;
    public Vehicle(String modelName, String brand) {
        this.modelName = modelName;
        this.brand = brand;
    }
    public void startEngine() {
        System.out.println(“Engine started for “ + modelName + “!”);
    }
    public void stopEngine() {
        System.out.println(“Engine stopped for “ + modelName + “.”);
    }
}
// 자식 클래스
class Car extends Vehicle {
    private int numberOfDoors;
    public Car(String modelName, String brand, int numberOfDoors) {
        super(modelName, brand);
        this.numberOfDoors = numberOfDoors;
    }
    public int getNumberOfDoors() {
        return numberOfDoors;
    }
    // 메서드 오버라이딩
    @Override
    public void startEngine() {
        System.out.println(“Car engine started for “ + modelName + “!”);
    }
}
cs

 

상속 활용 모범 사례

활용 방법 설명
코드 재사용 공통 기능을 부모 클래스에 구현하여 중복 코드 제거
메서드 오버라이딩 부모 클래스의 메서드를 자식 클래스에서 재정의하여 특화된 동작 구현
super 키워드 활용 부모 클래스의 메서드를 호출하여 기능 확장
protected 접근 제어자 자식 클래스에서만 접근 가능한 멤버 정의

상속의 주의점

상속보다 합성(Composition)을 선호하는 것이 좋습니다. 상속은 강한 결합도를 만들어 유연성을 제한할 수 있으므로, 적절한 상황에서만 사용해야 합니다.

 

다형성(Polymorphism)의 실전 활용

다형성은 동일한 인터페이스를 통해 다양한 객체가 각자의 방식으로 응답할 수 있는 능력을 의미합니다. 다형성은 코드의 유연성과 확장성을 크게 향상시킵니다.

 

실제 예제: 도형 그리기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 부모 클래스
class Polygon {
    public void render() {
        System.out.println(“Rendering Polygon…”);
    }
}
// 자식 클래스들
class Square extends Polygon {
    @Override
    public void render() {
        System.out.println(“Rendering Square…”);
    }
}
class Circle extends Polygon {
    @Override
    public void render() {
        System.out.println(“Rendering Circle…”);
    }
}
// 다형성 활용
public class Main {
    public static void main(String[] args) {
        // 다형적 변수 선언
        Polygon polygon = new Polygon();
        Polygon square = new Square();
        Polygon circle = new Circle();
        // 동일한 메서드 호출, 다른 결과
        polygon.render(); // “Rendering Polygon…”
        square.render();  // “Rendering Square…”
        circle.render();  // “Rendering Circle…”
        // 다형성을 활용한 메서드
        renderShape(new Square());
        renderShape(new Circle());
    }
    public static void renderShape(Polygon shape) {
        shape.render();
    }
}
cs

 

다형성의 두 가지 유형

유형 설명 예시
메서드 오버라이딩 자식 클래스에서 부모 클래스의 메서드를 재정의 위 예제의 render() 메서드
메서드 오버로딩 같은 이름의 메서드를 다른 매개변수로 정의 add(int a, int b)add(double a, double b, double c)

캡슐화(Encapsulation)의 실전 활용

캡슐화는 데이터와 메서드를 하나로 묶고, 외부에서의 접근을 제한하는 것입니다.

이를 통해 데이터 무결성을 보호하고 코드의 유지보수성을 향상시킵니다.

 

실제 예제: 직원 정보 관리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class Employee {
    // 비공개 변수 (데이터 은닉)
    private int ssn;
    private String empName;
    private int empAge;
    // Getter와 Setter 메서드
    public int getEmpSSN() {
        return ssn;
    }
    public String getEmpName() {
        return empName;
    }
    public int getEmpAge() {
        return empAge;
    }
    public void setEmpAge(int newValue) {
        if (newValue > 0 && newValue < 120) { // 유효성 검사
            empAge = newValue;
        } else {
            throw new IllegalArgumentException(“Invalid age value”);
        }
    }
    public void setEmpName(String newValue) {
        if (newValue != null && !newValue.isEmpty()) {
            empName = newValue;
        } else {
            throw new IllegalArgumentException(“Name cannot be empty”);
        }
    }
    public void setEmpSSN(int newValue) {
        // 실제로는 더 복잡한 유효성 검사가 필요
        ssn = newValue;
    }
}
cs

 

캡슐화의 이점

이점 설명
데이터 보호 직접 접근을 제한하여 데이터 무결성 유지
유효성 검사 setter 메서드에서 입력 데이터 검증 가능
구현 변경 유연성 내부 구현 변경 시 외부 코드에 영향 최소화
사용 편의성 복잡한 내부 로직을 간단한 인터페이스로 제공

추상화(Abstraction)의 실전 활용

추상화는 복잡한 시스템에서 핵심적인 개념이나 기능을 간추려내는 과정입니다.

자바에서는 추상 클래스와 인터페이스를 통해 추상화를 구현합니다.

 

실제 예제: 동물 소리 내기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 추상 클래스
abstract class Animal {
    // 추상 메서드 (구현 없음)
    public abstract void makeSound();
    // 일반 메서드
    public void sleep() {
        System.out.println(“Zzz…”);
    }
}
// 구체 클래스
class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println(“Woof”);
    }
}
class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println(“Meow”);
    }
}
// 추상화 활용
public class Main {
    public static void main(String[] args) {
        // Animal 직접 인스턴스화 불가
        // Animal animal = new Animal(); // 오류!
        Animal dog = new Dog();
        Animal cat = new Cat();
        dog.makeSound(); // “Woof”
        dog.sleep();     // “Zzz…”
        cat.makeSound(); // “Meow”
        cat.sleep();     // “Zzz…”
    }
}
cs

 

추상화 구현 방법

방법 특징 사용 시기
추상 클래스 일부 구현 제공 가능, 단일 상속만 가능 관련 클래스들의 공통 기능 구현 시
인터페이스 메서드 시그니처만 정의, 다중 구현 가능 클래스들 간의 계약 정의 시

추상화 활용 모범 사례

  1. 인터페이스에 프로그래밍하라: 구체적인 구현보다 추상 인터페이스에 의존하여 유연성 확보

  2. 적절한 추상화 수준 선택: 너무 추상적이거나 구체적이지 않은 적절한 수준 유지

  3. 명확한 책임 분리: 각 추상 클래스나 인터페이스가 단일 책임을 갖도록 설계

 

실전 종합 예제: 도형 그리기 애플리케이션

다음 예제는 네 가지 원칙을 모두 활용한 종합 예제입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// 인터페이스 (추상화)
interface Shape {
    double getArea();
    double getPerimeter();
}
// 추상 클래스 (추상화)
abstract class AbstractShape implements Shape {
    private String color;
    public AbstractShape(String color) {
        this.color = color;
    }
    public String getColor() {
        return color;
    }
    public void showColor() {
        System.out.println(“Color: “ + color);
    }
    // 추상 메서드
    public abstract void draw();
}
// 구체 클래스 (상속, 다형성)
class Circle extends AbstractShape {
    private double radius;
    public Circle(String color, double radius) {
        super(color);
        this.radius = radius;
    }
    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
    @Override
    public double getPerimeter() {
        return 2 * Math.PI * radius;
    }
    @Override
    public void draw() {
        System.out.println(“Drawing a circle.”);
    }
}
class Rectangle extends AbstractShape {
    // 캡슐화
    private double width, height;
    public Rectangle(String color, double width, double height) {
        super(color);
        this.width = width;
        this.height = height;
    }
    @Override
    public double getArea() {
        return width * height;
    }
    @Override
    public double getPerimeter() {
        return 2 * (width + height);
    }
    @Override
    public void draw() {
        System.out.println(“Drawing a rectangle.”);
    }
}
cs

 

객체지향 프로그래밍의 네 가지 핵심 원칙인 상속, 다형성, 캡슐화, 추상화는 서로 밀접하게 연관되어 있으며, 함께 사용될 때 가장 큰 효과를 발휘합니다.

이러한 원칙들을 적절히 활용하면 코드의 재사용성, 유지보수성, 확장성을 크게 향상시킬 수 있습니다

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다