230809 1탄.객체지향프로그램(OOP)
객체지향프로그램(Object Oriented Programming, OOP)
: 객체(Object)를 가지고 프로그래밍(Programming)하는것을 말하는데
- 객체(Object)라는 것은 커피,술,담배,게임,자동차,질병 같이 유,무형의 어떤 대상을 지칭하는것을 말한다.
객체(Object)는 상태(state)와 기능(behavior)을 가지고 있는데
예를들어 버스(Bus)라는 객체가 있다고 생각했을때
상태(state)를 버스가 가진 속성,특징이라고 생각해보자 버스(Bus)는 색깔,출발지,도착지,번호판등 매우 많은 상태를 가지고있고, 우리는 이걸 변수라는 이름으로 쓸 수 있겠다.
기능(behavior)은 그 변수를 가진 객체가 행하는 행위를 말하는데 버스(Bus)는 시동을켜기도 하고 어딘가로 움직이기도 하는데 이 모든 행위를 말한다.
즉, 어떤 특징(state)을 가지고 어떤 행위(behavior)를 하는 객체(Object)라는 애를 가지고 코드를 짜는 행위를 객체 지향프로그램 이라고 한다.
색깔,출발지,도착지,번호판을 가지고 있고(변수) 시동을 걸고 어딘가로 움직이는(함수)를 가진 버스(Object)는 또 고속버스(ExpressBus), 광역버스(WideBus), 시내버스(CityBus) 처럼 여러 종류가 있다.
만약 고속버스(ExpressBus), 광역버스(WideBus), 시내버스(CityBus) 를 이용해서 코드를 짠다고 했을때 모든 변수를 각각 선언해주고 값을 넣어주고, 모든 함수들을 각각 만들어 준다면, 수정이 필요할때 그렇게 각각만든 곳에가서 직접 수정해줘야 하는 상황이 발생할 것이다. 만약 버스의 종류가 수백, 수천가지라면 그걸 일일이 가서 하나씩 수정할 것인가?
그런것들이 귀찮아서 하는것이 객체지향프로그램(OOP)이고 4가지특징(추상화,상속,다형성,캡슐화)이 있는데
버스로 예를들면서 같이 공부해보자.
1. 추상화 클래스 :상속가능, 추상화클래스를 상속받는 클래스들은 반드시 추상메소드를 써야됨
package com.android.oop
fun main(){
val expressBus = ExpressBus()
expressBus.engineStart()
expressBus.departure()
ExpressBus().engineStart()
ExpressBus().departure()
}
abstract class Bus() {
abstract fun engineStart()
open fun departure() {
println("출발합니다.")
}
}
class ExpressBus:
Bus() {
override fun engineStart() {
println("부릉부릉")
}
override fun departure() {
super.departure()
}
}
▼추상화 클래스▼
ㄱ. 추상화는 abstract를 클래스에 붙여주면 추상화 클래스, abstract를 매소드에 붙여주면 추상화 메소드이다.(open이랑 비슷한부분은 상속을 한다는것이고 전혀 다른개념이다.)
ㄴ. 위 코드에서 Bus()클래스는 추상화클래스이고 engineStart()만 추상화 매소드이다. 얘는 중괄호{}를 쓸 수 없다. 무조건 저상태로 나둬라 말그대로 기능이없는애를 각 클래스에서 가져다가 기능을 추가해주는거다.
ㄷ. 추상화(abstract)클래스에서는 open메소드를 사용가능하지만, open클래스에서는 추상화메소드(abstract)를 쓸 수 없다.
ㄹ. 추상화클래스의 추상화 메소드를 사용하면 어떤 일이 발생하냐면 추상클래스를 상속받는 모든 모든 클래스들이 반드시 추상화 메소드(abstract)를 사용해야한다.
ㅂ. 이게 먼말이냐면 추상화클래스(Bus)를 상속받는 ExpressBus클래스에서 반드시 추상화메소드(engineStart)를 override해줘야한다는소리다. 안쓰면안된다 무조건 써야된다. 그리고 기능을 넣어주면된다.
ㅅ. 먼가 불편하다고 생각되면 그게 맞다. 처음에 나도 도대채 이걸 왜써야 되냐고 생각되었다. 그냥 open클래스를쓰고 open메소드를 써서 필요하면 쓰고 불필요하면 안쓰면되는데 도대채 왜쓰는거냐?
ㅇ. 추상화 메소드는 위에서 말했듯이 추상화클래스를 상속받는 모든 클래스는 반드시 써야한다. 실무에 들어가면 많은사람들이 같이 코딩을 하는데 반드시 써야되는 추상화 메소드를 안쓰면 바로 에러가뜨기때문에 누가 어디서 빼먹었는지 바로 체크가 가능하다.
ㅈ. 또한 어떤 공통적인 기능을 추가할때 추상화 메소드를 추가해주면 그것도 반드시 추가해서 써야되기때문에 바로바로 체크가 가능한 부분이다.
ㅊ. 이유는 더 많겠지만 일단 반드시 써야하므로 규칙적이고 빼먹지않을 수 있게 체크하는 부분에있어서 무조건 써야하는 메소드라면 추상메소드를 쓰는게 많은 도움이 될것같다. 왜냐하면 나처럼 초보들은 빼먹는게 일상적이기 때문이다.
▼잡설▼
ㄱ. main함수에 보면 ExpressBus() 인스턴스를 생성해서 그걸 변수expressBus에 넣어줘서 변수expressBus를 이용해서 expressBus.engineStrart(), expressBus.departure() 와 같이 Bus클래스에있는 함수들을 사용하고 있는데
이건 인스턴스를 한번만 생성했기때문에 초기화가 한번만 된다. 즉, 열린 인스턴스를 계속 사용할 수 있다는 말이고
ㄴ. ExpressBus().engineStart(), ExpressBus().departure() 와 같이 인스턴스 생성하고 Bus클래스에 있는 함수 들을 사용하면 인스턴스가 2번이나 생성되서 초기화가 2번된다. 즉, engineStart()에서 열었던 인스턴스를 더 이상 사용할 수 없고, 두번째 열린 인스턴스를 사용할 수 밖에 없다.
ㄷ. 그래서 보통 ㄱ처럼 변수에 인스턴스를 할당하고 그 변수를 이용해서 코드를 작성한다. 이걸 말하는 이유는 나처럼 아예 맹탕인 사람들은 귀찮게 (ㄱ)처럼 변수에 인스턴스를 넣어서 사용하는것보다 (ㄴ)처럼 사용하는 사람이 있을 수 있기때문에 말했다.
2. open클래스 : 상속가능,open클래스를 상속받았다고해서 무조건 open메소드를 쓸 필요없음.필요한애들만 가져다쓰면됨
fun main(){
val expressBus = ExpressBus()
expressBus.engineStart()
expressBus.departure()
}
open class Bus() {
fun engineStart() {
println("부릉부릉")
}
open fun departure() {
println("출발합니다.")
}
open fun aircon(){
println("에어컨이 틀어져있습니다.")
println("창문을 닫아주세요.")
}
}
class ExpressBus:
Bus() {
override fun departure() {
super.departure()
}
}
ㄱ. open클래스의 open메소드들은 상속을 하는점에서 추상화 클래스와 비슷하지만 open클래스를 상속받았다고해서 무조건 open메소드를 써야되는게 아니다.
ㄴ. 위 코드를 보면 부모클래스(Bus)에 open 메소드가 두개가있다. (departure, aircon)
ㄷ. 그런데 상속받는 자식클래스(ExpressBus)에서 가져다쓴건 departure메소드 밖에없다. 이 부분이 추상클래스와 다른 부분이다.
ㄹ. 말그대로 필요한 애들만 가져다 쓰면되므로 추상화 클래스 보다 범용성이 훨씬 좋다.
ㅁ. 다만 클래스가 수십 수백개로 많아졌을때 빼먹으면 찾기가 매우힘들다.
ㅂ. 그러므로 반드시 써야되고 빼먹으면 안되는 상황일땐 추상화 메소드를 쓰고 내용이 간단하고 혼자할땐 open이 범용성이 좋아서 open클래스를 쓰면 될것같다.
ㅅ. 그런데 나같은 애들은 여기서 의문점이 생길것이다. 아니 추상화 클래스(abstract)는 추상화메소드(abstract)와 open메소드 둘다 쓸수 있으면 애초에 추상화 클래스(abstract)를 쓴다음 필요하면 추상화메소드(abstract)를 쓰고, open메소드를 쓰면 되지않냐? open클래스를 쓰면 추상화메소드(abstract)를 못쓰는데 도대채 왜? 구지? 쓰는거냐?
ㅇ. 이것도 이유가 있다. 위 코드에서 main함수에서 Bus().aircon(), Bus().engineStart()를 써봐라 사용가능하다.
ㅈ. 그런데 open클래스를 abstract로 바꾼다음 똑같이 main함수에서 Bus().aircon(), Bus().engineStart()를 써봐라 안된다.
ㅊ. 결론은 open클래스는 다이렉트로 인스턴스 생성이 가능하지만, 추상화 클래스는 다이렉트로 인스턴스 생성이 불가능하다. 추상화 클래스는 반드시 하위 클래스를 생성해서 그걸로 인스턴스를 생성해야한다.
1. 추상화
2. 상속
으로 나누지않고
1. 추상화(abstract) 클래스
2. open클래스
로 나눈 이유는 앞에거처럼 나누면 뭔가 추상화 클래스는 상속할 수 없는거 처럼 느껴져서 이렇게 나누었다.
▶2탄에서는 interface와 함께공부한 내용으로 간단한 예제를 다뤄보도록 하자.▶