객체지향 프로그래밍(Object-Oriented Programming, OOP)
– 객체지향 프로그래밍이란 무엇인가?
객체 지향 프로그래밍은 컴퓨터 프로그래밍 패러다임중 하나로, 프로그래밍에서 필요한 데이터를 추상화시켜 상태와 행동을 가진 객체를 만들고 그 객체들 간의 유기적인 상호작용을 통해 로직을 구성하는 프로그래밍 방법이다.
라고 하는데… 복잡하군요. 하나씩 풀어보도록 합니다.
– 객체란 무엇인가?
객체
일반적으로 명사가 객체가 됩니다.
쇼핑몰에서, 고객이 상품을 장바구니에 담는다
라는 로직을 구현해 봅니다.
public class Customer { /* ... */ }
public class Product { /* ... */ }
public class ShoppingCart { /* ... */ }
public class TicketProduct extends Product { /* ... */ }
명사인 고객
, 상품
, 장바구니
가 각각 객체가 됩니다.
객체와 클래스가 자주 오해를 가져오는데… 간단히 객체는 개념이고, 클래스는 자바에서 사용하는 구현체입니다. javascript 같은 경우 class 가 아니라 function 이 객체의 기능을 하게 됩니다.
상태와 행동
상태와 행동을 가진 객체
는 무슨 의미일까요?
행동은 객체의 존재 이유입니다. 위에서는 장바구니에 담는 것
이 행동이 됩니다. 그리고, 상태는 행동에 의해 변경되는 데이타의 모음입니다.
String userId = "skyer9@gmail.com";
long toyId = 11112222;
long bookId = 33334444;
long ticketId = 55556666;
LocalDateTime showTime = LocalDateTime.of(2020, 5, 15, 17, 30);
Customer customer = new Customer(userId);
Product toy = new Product(toyId, "장난감", new BigDecimal(5000));
Product book = new Product(bookId, "책", new BigDecimal(20000));
TicketProduct ticket = new TicketProduct(ticketId, "티켓", new BigDecimal(12000), showTime);
customer.addToCart(toy);
customer.addToCart(book);
customer.addToCart(ticket);
여기서 중요한 것은 행동이 먼저이고, 상태는 부수적인 것이라는 점입니다.
addToCart()
를 구현하다 보니 Customer
가 ShoppingCart
를 가지고 있어야 하는 것이지, 그 반대는 아니라는 것입니다.
– 추상화와 캡슐화
추상화(자료의 추상화)
위에서 Customer
가 상품정보를 어떤 형태로 보관하고 있는지는 다른 객체는 전혀 알 수 없습니다.(물론 알 필요도 없습니다.)
이런 추상화가 불편해 보일 수 있지만 캡슐화
를 설명하면서 왜 좋은 특징이 되는지 설명합니다.
캡슐화
데이타가 추상화 되어 있기 때문에 Customer
객체는 다른 객체를 전혀 고려하지 않고 자유로이 상품정보의 보관방식을 변경할 수 있습니다.
ArrayList<Product>
에 막바로 보관할 수도 있고, ShoppingCart
객체를 생성해서 보관할 수도 있습니다.
소스의 변경이 필요한 시점에 고려해야 할 범위를 제한할 수 있다는 것은 매우 좋은 장점이 됩니다.
– 상속
상속은 부모객체의 속성과 기능을 그대로 이어받아 사용할 수 있게하고, 기능의 일부분을 변경해야 할 경우, 상속받은 자식클래스에서 해당 기능만 다시 수정(정의)하여 사용할 수 있게 하는 것입니다.
public class TicketProduct extends Product {
private LocalDateTime showTime;
public TicketProduct(long productId, String productName, BigDecimal price, LocalDateTime showTime) {
super(productId, productName, price);
this.showTime = showTime;
}
}
TicketProduct
은 Product
을 상속받아 공연시간을 추가하고 있습니다.
상속과 사용
여기서 구분해야 할 것은 상속
과 사용
입니다.
객체 자체를 확장해서 쓸 때는 상속을 해야하고, 객체를 단지 이용만 하는 경우(위에서 Customer 가 ShoppingCart 를 이용하는 경우)는 상속이 아니라, 속성에 객체를 추가해서 사용하기만 하면 됩니다.
상속(extends) 과 인터페이스(interface)
상속과 유사하지만 구별되는 것이 interface
입니다. 상속은 코드를 공유하지만, interface 는 코드의 공유가 전혀 없는 것이 차이점입니다.
– 다형성
오버라이딩(Overriding)
부모 객체의 메소드를 재정의하는 것을 말합니다.
public class Money {
// ...
@Override
public String toString() {
return "wallet.Money{" +
"amount=" + amount +
", currencyCode='" + currencyCode + '\'' +
'}';
}
}
public class Mileage extends Money {
// ...
@Override
public String toString() {
return "wallet.Mileage{" +
"amount=" + this.getAmount() +
", currencyCode='" + this.getCurrencyCode() + '\'' +
'}';
}
}
오버로딩(Overloading)
동일한 메소드명으로, 서로 다른 타입 또는 갯수의 파라미터를 받는 것을 말합니다.
public class Money {
// ...
public Money add(Money _amount) {
// ...
}
public Money add(long _amount) {
// ...
}
public Money add(BigDecimal _amount) {
// ...
}
// ...
}
위에서 보면 add()
함수는 여러 파라미터를 받고 있습니다.