캡슐화
속성과 행위를 외부와 분리하는 것을 의미한다. 말 그대로 캡슐처럼 묶어서 분리하는 개념을 캡슐화(Encapsulation)라고 한다. 속성을 변수에, 행위를 메소드에, 캡슐을 클래스에 빗댈 수 있다. 이런 구조로 외부 코드가 데이터에 직접 접근하지 못하도록 방어막 역할을 하고 내부 상태는 private으로, 외부에는 public 메소드를 노출하여 정보를 은닉할 수 있다. 이렇게 하면 느슨한 결합(Loose Coupling)이 가능하다. 예를 들어 내부에서 변수명을 변경하는 등의 변화가 있어도 외부 메소드는 변함이 없기 때문에 의존성이 낮으며 모듈 수정이 비교적 자유롭다. 또한 재사용이 가능하며 테스트도 쉽다. 해당 메소드가 잘 동작하는지만 확인하면 되기 때문이다.
Getter/Setter 메소드를 이용한 캡슐화의 예다.
public class Encapsulation {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Java
복사
이처럼 name 변수에 직접 접근하지 않고 반드시 setName() 메소드로 변경을, getName() 메소드로는 조회를 진행하는 방식이 캡슐화에 대표적인 예라고 할 수 있다.
추상화
복잡한 시스템에서 핵심적인 개념 또는 기능을 간추려내는 것을 추상화(Abstraction)라고 한다. 즉 수행하는 방법이 아니라 수행하는 일 자체에 집중해 복잡도를 낮추는 것이다.
자동차는 매우 복잡한 기계다. 하지만 운전자는 자동차라는 기계에 대해 자세히 몰라도 운전하는 데 아무 문제가 없다. 핸들은 방향 전환에 대한 추상화, 액셀은 가속에 대한 추상화, 브레이크는 감속에 대한 추상화가 이미 정의되어 있기 때문이다. 승용차가 아니라 트럭을, 혹은 가솔린 차량이 아닌 전기차를 운전하더라도, 핸들과 액셀과 브레이크는 모두 동일한 역할을 하기에 각각의 역할만 잘 이해하면 된다. 내부적으로는 서로 다르게 구현되어 있겠지만 이 모든 복잡한 부분을 숨기고 운전자에게는 항상 동일한 인터페이스를 제공한다.
이 외에도 추상화 레벨(자동차의 경우라면 페달 단위 등)을 통일하면 체계적으로 개발(자동차의 경우라면 자동차 자체를 개발)할 수 있고, 무엇보다 내부 구현의 개선도 가능하다. 예를 들어, 좋은 자동차라면 브레이크는 감속을 한다는 인터페이스는 동일하게 유지하면서(추상화) 브레이크의 성능은 더욱 높일 수 있다(내부 구현 개선).
추상화가 지나치면 오히려 코드를 이해하기 어렵고, 활용하기는 훨씬 더 어렵다. if else로 해결할 수 있는 문제를 추상화로 적용할 수는 없지 않은가.
추상화 관련 풍자 프로젝트 사례: FizzBuzz Enterprise Edition
상속
한 객체가 또 다른 객체가 이어받는 것을 상속(Inheritance)이라고 하며, 부모의 재산을 자식이 상속받는 것과 같은 의미다. 자동차의 예를 들어 설명하자면, 어떤 회사에서 A라는 자동차를 만들면서 좋은 엔진과 좋은 브레이크를 만들었다고 가정해보자. 이제 B라는 자동차를 만들 때 A 자동차를 상속받으면 A 자동차의 좋은 엔진과 브레이크를 그대로 사용할 수 있다. 자동차 디자인 등 반드시 변경이 필요한 부분만 추가로 구현하면, 기존의 좋은 기능들은 굳이 새로 만들지 않고도 그대로 사용할 수 있는 것이다. 실무에서는 이 같은 상속이 매우 빈번하게 쓰여서 부모 클래스에 범용적인 부분을 만들어두고 자식 클래스가 상속받아 재사용하는 것이다.
다형성
다형성은 경우에 따라 객체가 다르게 동작하거나 또는 어떤 동작을 다른 방법으로 동작하게 하는 개념인데, 구체적으로는 메서드 오버로딩(Overloading)과 오버라이딩(Overriding)이 이에 해당한다. 오버로딩은 이름은 같지만 파라미터가 다른 메소드(경우에 따라 다르게 동작)를 말하며, 오버라이딩은 상속을 받아서 메소드를 재정의(어떤 동작을 다른 방법으로 동작)하는 것을 말한다. 유연하게 변하는 객체의 다형성은 OOP에서 매우 중요한 개념이며, 코드 중복을 줄이고 변경과 확장에 유연한 객체 지향적인 코드를 작성할 수 있게 해준다.
접근 제어자
•
public - 어디서나 접근할 수 있다. 접근 제한이 없으며 모두 열려 있다.
public class AccessModifiers {
public int MultiplyTwoNumbers(int a, int b) {
return a * b;
}
}
Java
복사
•
private - 클래스 내에서만 접근할 수 있다.
public class AccessModifiers {
private int MultiplyTwoNumbers(int a, int b) {
return a * b;
}
}
Java
복사
•
protected - 상속받은 클래스이거나 같은 패키지에서만 접근할 수 있다.
public class AccessModifiers {
protected int MultiplyTwoNumbers(int a, int b) {
return a * b;
}
}
Java
복사
•
default
◦
자바에서 접근 제어자를 부여하지 않으면 디폴트(기본)가 되며, 디폴트는 패키지 제한이다.
◦
즉 동일 패키지에서만 다른 클래스 접근이 가능하다.
package example;
class AccessModifiers {
int MultiplyTwoNumbers(int a, int b) {
return a * b;
}
}
Java
복사