OOP(Object-Oriented Programming)는 프로그램을 객체 단위로 나누어 개발하는 패러다임이다.
현실 세계의 개념을 프로그램에 반영해 데이터(속성)와 행동(메서드)를 하나의 객체로 묶어 처리합니다. 이를 통해 코드의 재사용성과 유지보수성을 높이며, 현실 세계의 문제를 모델링하기 쉽습니다.
OOP의 핵심 개념에는 추상화 , 캡슐화 , 다형성, 상속 이 있습니다.
추상화는 불필요한 세부 사항을 감추고 필요한 정보만 노출하는 개념이다.
추상화의 장점: 추상화를 통해 다양한 객체의 공통적인 부분만을 뽑아내어 코드의 일관성을 높이고 유지보수를 쉽게 할 수 있습니다. 즉, 코드에서 꼭 필요한 기능만 노출하고 세부 구현은 감추어 복잡성을 줄일 수 있습니다.
예를 들어, Vehicle 추상 클래스를 통해 Car와 Bicycle 등 공통의 기능만 정의하고 세부 사항은 각각 구현하게 함으로써 핵심 기능에 집중할 수 있습니다. 이를 통해 코드를 단순화하고, 객체 간의 공통적인 구조를 효과적으로 모델링할 수 있습니다.
캡슐화는 객체 내부의 데이터와 메서드를 외부에서 직접 접근하지 못하도록 보호하는 개념이다.
캡슐화의 장점: 데이터의 보호와 일관성을 유지할 수 있어 코드의 안전성이 높아지고, 외부에서 데이터에 접근하려면 특정 메서드를 통해야 하므로 객체의 동작 방식을 제어할 수 있습니다.
private 키워드를 사용해 클래스 내부 변수는 숨기고, 필요한 경우에만 getter나 setter 메서드로 접근을 허용합니다. 이를 통해 데이터 무결성을 유지하고 객체의 일관성을 보장할 수 있습니다.
오버로딩은 메서드 이름이 같지만 파라미터가 다른 경우이고, 오버라이딩은 상속받은 메서드를 재정의하는 것이다.
오버로딩은 같은 클래스 안에서 동일한 이름의 메서드를 파라미터 타입이나 개수에 따라 여러 개 정의하는 방식입니다. 예를 들어 print(int)와 print(String)처럼 파라미터에 따라 다른 동작을 수행하도록 설정할 수 있습니다.
오버라이딩은 부모 클래스에 정의된 메서드를 자식 클래스에서 다시 정의하는 것으로, 부모 클래스의 메서드를 재사용하면서 자식 클래스에 맞는 동작을 구현하는 방식입니다.
다형성은 같은 타입의 객체가 여러 형태를 가질 수 있는 성질로, 상속과 인터페이스를 통해 구현되며 코드의 유연성을 높여준다.
다형성(Polymorphism)은 하나의 부모 클래스 타입(인터페이스, 클래스)로 여러 자식 클래스 객체를 참조할 수 있게 해줍니다.
이를 통해, 부모 클래스나 인터페이스를 통해 다양한 객체를 동일한 방식으로 다룰 수 있어 코드 재사용성과 유지보수가 개선됩니다.
예를 들어, Animal 타입 변수로 Dog, Cat 객체를 다루어 상황에 따라 다양한 동작을 구현할 수 있습니다.
상속은 부모 클래스의 기능과 속성을 자식 클래스가 물려받는 개념이다.
상속(Inheritance)은 기존 클래스(부모 클래스)의 기능을 새로운 클래스(자식 클래스)가 그대로 물려받아 사용할 수 있게 해줍니다. 자식 클래스는 부모 클래스의 필드와 메서드를 재사용하고 필요에 따라 재정의할 수 있어, 코드 중복을 줄이고 관계를 자연스럽게 표현할 수 있습니다.
상속은 부모 클래스에 대한 강한 결합을 만들고, 변경 시 자식 클래스에도 영향을 미친다.
상속은 부모와 자식 클래스 간의 결합도가 높아 부모 클래스가 변경되면 자식 클래스에서도 예상치 못한 오류가 발생할 수 있습니다.
또한 상속 관계가 복잡해질수록 코드 이해와 유지보수가 어려워질 수 있어, 불필요한 상속을 피하는 것이 좋습니다.
상속은 is-a 관계를, 조합은 has-a 관계를 표현한다.
상속은 특정 클래스가 상위 클래스의 일종일 때, 즉 is-a 관계일 때 적합합니다. 예를 들어 Bird는 Animal의 한 종류이므로 상속을 사용하는 것이 자연스럽습니다.
반면, 조합(Composition)은 클래스가 다른 객체를 포함할 때, 즉 has-a 관계에 적합합니다. 예를 들어 Car 클래스가 Engine 클래스를 포함하는 경우, 조합이 더 적합합니다.
조합(Composition)은 객체 지향 프로그래밍에서 한 클래스가 다른 클래스의 객체를 멤버 변수로 가지는 방식입니다. 조합을 사용하면 상속과 달리 클래스 간의 강한 결합도가 줄어들기 때문에 유연성이 높아집니다
인스턴스 검사용 연산자로, 자바에서 객체가 특정 클래스나 그 클래스의 자식 클래스의 인스턴스인지 확인하는 데 사용됩니다.
객체가 어떤 클래스 또는 그 클래스의 자식 클래스인지 검사할 때 유용하며, 안전하게 타입을 확인하고 형변환할 수 있도록 도와줍니다.
예를 들어, if (obj instanceof Car)와 같은 조건문으로 obj가 Car 타입인지 확인할 수 있습니다.
유연성이 떨어지고, 코드의 가독성과 유지보수성 저하, 성능 문제 등이 생길 수 있다.
instanceof를 과도하게 사용하면 코드가 특정 타입에 의존하게 되어 유연성이 떨어지고, 유지보수가 어려워지고, 다형성의 장점을 잃게 됩니다. If 등의 조건문을 통해 가독성과 유지보수성이 저하되고, 자주 호출될 시 성능에 문제를 일으킬 수 있습니다.
객체의 구체적인 타입을 직접 확인하지 않고, 인터페이스나 상위 클래스 메서드를 통해 처리하는 것이 더 좋은 설계가 될 수 있습니다. 다시말해 instanceof 대신 각 클래스에서 특정 메서드를 오버라이딩하여 자신만의 동작을 구현하는 방식이 있습니다.
interface는 클래스가 구현해야 할 메서드들의 틀만 정의하는 일종의 계약서 같은 개념이다.
여러 클래스가 공통으로 가져야 할 기능을 정의할 때 유용합니다. 또 다중 상속을 지원하여 다양한 기능을 클래스에 자유롭게 추가할 수 있습니다.
interface를 구현한 클래스는 반드시 추상 메서드는 반드시 오버라이딩해야 합니다.
interface는 오로지 메서드의 선언만, abstract class는 메서드 선언과 일부 구현도 포함할 수 있다.
interface는 메서드 선언만 가능하고, 한 클래스가 여러 인터페이스를 구현 (implements)할 수 있습니다.
abstract class는 일반 인스턴스 필드와 구현된 메서드를 포함할 수 있어, 일부 기능을 미리 정의할 수 있습니다. 이때 추상 메서드(구현 없는 메서드)와 일반 메서드(구현이 있는 메서드)를 함께 가질 수 있습니다. 단일 상속만 지원하므로, 한 클래스는 하나의 추상 클래스만 상속(extends)할 수 있습니다.
공통 규약만 필요한 경우 interface, 일부 구현이 필요한 경우 abstract class를 사용한다.
interface는 클래스 간의 강한 관련성이 없고, 필요한 기능만 자유롭게 붙였다 떼었다 할 때 적합합니다.
abstract class는 계층 구조가 명확하게 설정된 상황에서 공통된 특성과 기본 동작을 상속받게 할 때 유용합니다.
final 키워드는 변수, 메서드, 클래스에서 각각 변경 불가능하도록 제한할 때 사용된다.
변수에 final을 붙이면 초기화 후 값을 변경할 수 없고, 상수처럼 사용됩니다.
메서드에 final을 붙이면 자식 클래스에서 오버라이딩이 불가능합니다.
클래스에 final을 붙이면 상속을 막아, 클래스 자체를 변경 없이 그대로 사용할 수 있습니다.