Paradox Simulation

728x90
반응형

인터페이스와 추상 클래스

인터페이스(Interface)와 추상 클래스(Abstract Class)는 객체지향 프로그래밍에서 추상화를 구현하는 방법 중 하나입니다.

추상화란 객체의 공통적인 속성과 동작을 추출하여 클래스로 정의하는 것을 말합니다.

반응형

인터페이스

인터페이스는 일종의 계약서(contract)로, 클래스가 구현해야 할 메서드와 상수만을 정의한 것입니다.

인터페이스는 구현할 메서드의 선언만을 하고 구현부는 작성하지 않습니다.

 

public interface Printable {
    void print();
}

위 코드에서는 Printable 인터페이스를 정의하고, print() 메서드를 선언하고 있습니다.

이 인터페이스를 구현하는 클래스는 반드시 print() 메서드를 정의하여야 합니다.

 

public class ConsolePrinter implements Printable {
    @Override
    public void print() {
        System.out.println("콘솔에 출력합니다.");
    }
}

위 코드에서는 Printable 인터페이스를 구현하여, print() 메서드를 오버라이딩하여 콘솔에 출력하는 기능을 구현하였습니다.

인터페이스는 다중 상속이 가능합니다.

즉, 여러 개의 인터페이스를 상속받아 구현할 수 있습니다.

 

public interface Movable {
    void move();
}

public interface Attackable {
    void attack();
}

public class Knight implements Movable, Attackable {
    @Override
    public void move() {
        System.out.println("나이트가 이동합니다.");
    }

    @Override
    public void attack() {
        System.out.println("나이트가 공격합니다.");
    }
}

위 코드에서는 Movable과 Attackable 인터페이스를 구현하여 Knight 클래스를 정의하였습니다.

 

추상 클래스

추상 클래스는 일종의 미완성된 클래스로, 하나 이상의 추상 메서드(구현부가 없는 메서드)를 가지고 있는 클래스입니다.

추상 클래스는 직접 인스턴스를 생성할 수 없으며, 추상 클래스를 상속받아 구현하는 자식 클래스에서 추상 메서드를 반드시 구현하여야 합니다.

 

public abstract class Animal {
    private String name;

    public Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public abstract void move();
}

위 코드에서는 Animal 클래스를 추상 클래스로 정의하고 있습니다. 이 클래스는 추상 메서드인 move() 메서드를 선언하고 있습니다.

이 클래스를 상속받아 구현하는 자식 클래스에서는 move() 메서드를 구현하여야 합니다.

 

public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    @Override
    public void move() {
        System.out.println("걷습니다.");
    }
}

 

추상 클래스 vs 인터페이스

추상 클래스와 인터페이스는 추상화를 구현하는 방법 중 하나로 비슷한 개념이지만, 몇 가지 차이점이 있습니다.

 

메서드 구현 여부

추상 클래스는 추상 메서드 뿐만 아니라 구현된 일반 메서드도 가질 수 있습니다.

인터페이스는 추상 메서드만을 가질 수 있으며, 구현된 일반 메서드를 가질 수 없습니다.

 

인스턴스 생성 여부

추상 클래스는 직접 인스턴스를 생성할 수 없습니다.

반면에, 인터페이스는 인스턴스를 생성할 수 없습니다.

 

다중 상속 여부

추상 클래스는 단일 상속만을 지원합니다.  즉, 하나의 클래스만 상속받을 수 있습니다.

반면에, 인터페이스는 다중 상속을 지원합니다.

여러 개의 인터페이스를 상속받아 구현할 수 있습니다.

 

사용 용도

추상 클래스는 객체 간의 공통된 특성을 추상화하여 상속 계층을 구성하는 데 사용됩니다.

인터페이스는 객체 간의 통신 규약을 정의하는 데 사용됩니다.

즉, 인터페이스는 객체 간의 결합도를 낮추기 위한 용도로 사용됩니다.

 

추상화와 캡슐화

추상화

추상화는 객체에서 불필요한 정보를 제거하고 필요한 정보만을 남기는 것을 의미합니다.

객체를 추상화하기 위해서는 객체의 공통된 특징을 찾아내고 이를 모델링해야 합니다.

추상화를 통해 객체를 단순화하고 일반화시켜 유연하고 확장성 있는 코드를 작성할 수 있습니다.

 

캡슐화

캡슐화는 객체의 데이터와 이를 처리하는 메서드를 하나로 묶어서 외부로부터의 접근을 제어하는 것을 의미합니다.

캡슐화를 통해 객체의 내부 구현 방식을 감추고 객체 간의 결합도를 낮출 수 있습니다.

 

인터페이스와 추상 클래스의 개념

인터페이스

인터페이스는 객체의 동작 방식을 정의한 추상 타입입니다.

인터페이스는 메서드의 원형만 정의하고, 실제 구현은 이를 상속받는 클래스에서 수행합니다

인터페이스를 사용하면 객체 간의 결합도를 낮추고, 코드의 재사용성과 유지보수성을 높일 수 있습니다.

 

public interface Drawable {
    void draw();
}

public class Circle implements Drawable {
    @Override
    public void draw() {
        System.out.println("원을 그립니다.");
    }
}

public class Square implements Drawable {
    @Override
    public void draw() {
        System.out.println("사각형을 그립니다.");
    }
}

위의 코드에서는 Drawable 인터페이스를 정의하고, 이를 구현하는 Circle 클래스와 Square 클래스를 정의합니다.

인터페이스를 구현하는 클래스에서는 인터페이스에서 정의한 메서드를 반드시 구현해야 합니다.

 

추상 클래스

추상 클래스는 인스턴스를 생성할 수 없는 클래스입니다.

추상 클래스는 하나 이상의 추상 메서드를 포함하며, 이를 상속받은 클래스에서 반드시 구현해야 합니다.

추상 클래스는 인터페이스와 마찬가지로 객체 간의 결합도를 낮출 수 있으며, 클래스의 일반적인 특징을 추출하여 코드의 재사용성을 높일 수 있습니다.

 

public abstract class Shape {
    private int x;
    private int y;

    public Shape(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public abstract void draw();
}

public class Circle extends Shape {
    private int radius;

    public Circle(int x, int y, int radius) {
        super(x, y);
        this.radius = radius;
    }

    @Override
    public void draw() {
        System.out.println("원을그립니다.");
    }
}

public class Square extends Shape {
    private int width;
    
    public Square(int x, int y, int width) {
        super(x, y);
    	this.width = width;
	}

	@Override
	public void draw() {
    	System.out.println("사각형을 그립니다.");
	}
}

위의 코드에서는 Shape 추상 클래스를 정의하고, 이를 상속받는 Circle 클래스와 Square 클래스를 정의합니다.

추상 클래스에서는 추상 메서드를 정의하여 하위 클래스에서 반드시 구현해야 합니다.

 

인터페이스와 추상 클래스의 활용

인터페이스와 추상 클래스는 객체 지향 프로그래밍에서 자주 사용됩니다.

이들을 활용하여 유연하고 확장성 있는 코드를 작성할 수 있습니다.

 

인터페이스와 다형성

인터페이스를 사용하면 다형성을 구현할 수 있습니다.

다형성이란 하나의 객체가 여러 가지 형태를 가질 수 있는 성질을 의미합니다.

인터페이스를 구현하는 클래스는 인터페이스의 타입으로 선언될 수 있으며, 이를 통해 객체의 다형성을 구현할 수 있습니다.

 

public interface Animal {
    void makeSound();
}

public class Cat implements Animal {
    @Override
    public void makeSound() {
        System.out.println("야옹");
    }
}

public class Dog implements Animal {
    @Override
    public void makeSound() {
        System.out.println("멍멍");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Cat();
        animal.makeSound();

        animal = new Dog();
        animal.makeSound();
    }
}

위의 코드에서는 Animal 인터페이스를 정의하고, 이를 구현하는 Cat 클래스와 Dog 클래스를 정의합니다.

다형성을 구현하기 위해 Animal 타입으로 변수를 선언하고, 이를 통해 객체를 생성합니다.

이렇게 함으로써, Cat 객체와 Dog 객체를 동일한 타입으로 다룰 수 있습니다.

 

public abstract class Shape {
    protected int x;
    protected int y;

    public Shape(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public abstract double getArea();

    public void printInfo() {
        System.out.println("도형의 x 좌표: " + x);
        System.out.println("도형의 y 좌표: " + y);
        System.out.println("도형의 넓이: " + getArea());
    }
}

public class Circle extends Shape {
    private int radius;

    public Circle(int x, int y, int radius) {
        super(x, y);
        this.radius = radius;
    }

    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
}

public class Rectangle extends Shape {
    private int width;
    private int height;

    public Rectangle(int x, int y, int width, int height) {
        super(x, y);
        this.width = width;
        this.height = height;
    }

    @Override
    public double getArea() {
        return width * height;
    }
}

public class Main {
    public static void main(String[] args) {
        Circle circle = new Circle(0, 0, 5);
        Rectangle rectangle = new Rectangle(0, 0, 10, 5);

        circle.printInfo();
        rectangle.printInfo();
    }
}

위의 코드에서는 Shape 추상 클래스를 정의하고, 이를 상속받는 Circle 클래스와 Rectangle 클래스를 정의합니다.

Shape 클래스에는 x, y 필드와 getArea() 메서드가 선언되어 있으며, printInfo() 메서드는 구현되어 있습니다.

Circle 클래스와 Rectangle 클래스에서는 getArea() 메서드를 오버라이딩하여 각 도형의 넓이를 구합니다.

Main 클래스에서는 Circle 객체와 Rectangle 객체를 생성하고, printInfo() 메서드를 통해 각 도형의 정보를 출력합니다.

 

이를 실행하면 다음과 같은 결과가 출력됩니다.

도형의 x 좌표: 0
도형의 y 좌표: 0
도형의 넓이: 78.53981633974483
도형의 x 좌표: 0
도형의 y 좌표: 0
도형의 넓이: 50.0

Circle 클래스와 Rectangle 클래스는 Shape 추상 클래스를 상속받았기 때문에 Shape 클래스에서 선언된 필드와 메서드를 사용할 수 있습니다.

getArea() 메서드는 각 도형마다 구현이 다르기 때문에 추상 메서드로 선언되었습니다.

이를 각 도형 클래스에서 오버라이딩하여 구현합니다.

printInfo() 메서드는 모든 도형에서 공통적으로 사용할 수 있기 때문에 Shape 클래스에서 구현되어 있습니다.

 

캡슐화와 정보 은닉

객체지향 프로그래밍에서 중요한 개념 중 하나는 캡슐화(encapsulation)입니다.

캡슐화란 객체의 상태와 행위를 하나로 묶어서 외부에 노출시키지 않고 숨기는 것을 의미합니다.

이를 통해 객체의 내부 구현 방식을 감추고 외부에서 사용할 수 있는 인터페이스만 제공함으로써 객체의 안정성과 유지보수성을 높일 수 있습니다.

캡슐화를 구현하는 방법 중 하나는 정보 은닉(information hiding)입니다.

정보 은닉은 객체의 내부 상태를 외부에서 직접 접근할 수 없도록 하는 것을 말합니다.

이를 위해 객체의 필드를 private으로 선언하여 외부에서 직접 접근할 수 없게 만들고, 필요한 경우 public 메서드를 통해 필드에 접근하도록 합니다.

이렇게 하면 객체의 내부 상태를 보호하면서도 필요한 기능을 제공할 수 있습니다.

다음은 캡슐화와 정보 은닉을 적용한 예시 코드입니다.

 

public class Car {
    private int speed;
    private String color;

    public void setSpeed(int speed) {
        if (speed < 0) {
            this.speed = 0;
        } else {
            this.speed = speed;
        }
    }

    public int getSpeed() {
        return speed;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getColor() {
        return color;
    }
}

public class Main {
    public static void main(String[] args) {
        Car car = new Car();

        car.setSpeed(100);
        System.out.println("속도: " + car.getSpeed());

        car.setSpeed(-50);
        System.out.println("속도: " + car.getSpeed());

        car.setColor("Red");
        System.out.println("색상: " + car.getColor());
    }
}

위의 코드에서는 Car 클래스를 정의하고, speed와 color 필드를 private으로 선언합니다.

이를 외부에서 접근할 수 없도록 하고, setSpeed(), getSpeed(), setColor(), getColor() 메서드를 public으로 선언하여 필드에 접근하도록 합니다.

setSpeed() 메서드에서는 speed 값을 설정하면서 음수인 경우 0으로 설정하도록 합니다.

 

Main 클래스에서는 Car 객체를 생성하고, setSpeed(), getSpeed(), setColor(), getColor() 메서드를 통해 객체의 상태를 변경하고 출력합니다.

이를 실행하면 다음과 같은 결과가 출력됩니다.

 

속도: 100
속도: 0
색상: Red

 

마무리

객체지향 프로그래밍에서 캡슐화와 정보 은닉, 상속, 다형성 등의 개념을 이해하고 활용하는 것은 매우 중요합니다.

이를 통해 객체지향적인 프로그래밍을 할 수 있고, 좀 더 안정적이고 유지보수가 용이한 코드를 작성할 수 있습니다.

 

결론적으로, 객체지향 프로그래밍은 현실 세계를 모델링하여 코드로 옮기는 것을 목적으로 하는 프로그래밍 패러다임입니다.

이를 위해 객체, 클래스, 상속, 다형성, 추상화, 캡슐화, 정보 은닉 등의 개념과 기술을 사용합니다.

이를 잘 활용하면 유지보수성이 높은, 안정적이고 확장성이 좋은 코드를 작성할 수 있습니다.

 

하지만 객체지향 프로그래밍은 단순한 문법과 규칙을 익히는 것만으로는 충분하지 않습니다.

객체지향적 사고 방식과 설계 원칙을 이해하고, 이를 실제 코드 작성에 적용하는 것이 중요합니다.

따라서 객체지향 프로그래밍에 대한 학습과 이해를 꾸준히 진행하고, 다양한 프로젝트를 경험하며 개발 능력을 향상시켜 나가는 것이 필요합니다.

728x90
반응형
반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band
250x250