2016/03/06 - [java] - 추상화(Abstraction) 이해의 중요성 #2
추상화 이해의 중요성에 대한 3번째 글입니다. 2번째 글에선 자동차(Car)의 속성에 해당하는 Car.drivingDistance, Car.dateMadeAt, Car.Color, Car.Engine 등을 getter-setter method로 왜 Encapsulation(캡슐화)을 하는지 살펴보았습니다.
엔진(Engine)이라는 것도 생각해 보니 제조사가 어디인지 몇 마력인지 모델은 또 무엇인지 등 복잡한 정보를 가지고 있는 객체란 생각이 듭니다. Engine에 대한 추상화도 필요해 보입니다. 휠(Wheel), 제조사, 트렁크, 루프도 추상화가 필요해 보입니다. 쉽게 아래 테이블처럼 자동차 각 구성요소를 클래스로 추상화 할수 있습니다.
자동차 구성요소 | 추상(Abstraction) |
엔진(Engine) | Engine |
휠(Wheel) | Wheel |
제조사(Manufacturer) | Manufacturer |
트렁크(Trunk) | Trunk |
루프(Roof) | Roof |
여기서 주의해야 할 사항이 있습니다. 추상화를 너무 과도하게 하지 않는가 생각해 보아야 합니다. primitive type, String으로 충분히 요구사항을 만족시킬 수 있고 추후 요구사항 및 변화에도 유연할 수 있다면 클래스화 하지 않을 수도 있습니다. Oracle HotSpot 32bit JVM 기준으로 한 객체는 8 바이트의 헤더를 가지고 있고 배열(Array)은 12 바이트의 헤더를 가지고 있습니다. 즉, 하나의 객체는 최소 8byte 메모리를 소모하고 하나의 배열은 최소 12byte 메모리를 소모 합니다. 메모리를 고려해야할 시스템 환경이라면 클래스 대신 byte, boolean, char, short, int, float, long, double과 같은 primitive type과 String으로 쓰는 것을 고려할 수있습니다. 원래 Car 클래스가 String 멤버 변수로 이루어진 것처럼 말이지요.
이 글에서는 윗 테이블처럼 추상화를 했다고 가정합니다. Car.color는 int로 변경하고 Car.dateMadeAt은 java.util.Date 또는 java 8의 java.time.LocalDateTime을 사용할 수 있습니다. 그러나 Car.dateMadeAt을 memory efficient하게 사용하기 위해 String으로 사용하고 java.util.DateTime 이나 java.time.LocalDateTime으로 변환하는 메소드를 제공하도록 하겠습니다.
package com.jayjaylab.app.usedcar public class Car { int drivingDistance; // in km(killo meters) String dateMadeAt; // in 2007-12-03T10:15:30 format int color; Engine engine; Wheel wheel; Manufacturer manufacturer; String model; Trunk trunk; Roof roof; // and so on... public void setEngine(Engine engine) { this.engine = engine; } public void setWheel(Wheel wheel) { this.wheel = wheel; } public void setRoof(Roof Roof) { this.roof = roof; } public void setDrivingDistance(int drivingDistance) { this.drivingDistance = drivingDistance; } public java.util.Date getDateMadeAt() { return new java.util.Date(dateMadeAt); } public java.time.LocalDateTime getLocalDateTimeMadeAt() { return java.time.LocalDateTime.parse(dateMadeAt); } .... public static void main(String[] args) { Car car = new Car(); // 엔진 변경 car.setEngine(new Engine("yamato")); car.setEngine(new Engine("superengine")); // 휠 변경 car.setWheel(new Wheel("kumho_wheel")); car.setWheel(new Wheel("fantastic_wheel")); // 루프 변경 car.setRoof(new Roof("default_roof")); car.setRoof(new Roof("sun_roof")); // 주행 거리 변경. 불법 이죠잉! car.setDrivingDistance(100); // 100 km car.setDrivingDistance(200); // 200 km } }
자동차 중고매매 사업장에서의 쓰일 자동차 Abstraction이긴 한데, 개발사 회사의 입장으로선 굳이 자동차 매매만 되는 애플리케이션으로 한정시킬 필요가 없을것 같습니다. 추후에 자동차 뿐만 아니라 오토바이, 자전거등의 사업장에서도 사용될 수 있는 확장성을 좀 더 고려하면 개발한 제품을 공급할 곳이 더 많아지겠지요. 그래서 저는 Vehicle이란 인터페이스를 만들어서 Car, Bike가 상속하게 해야할지 Buyable이란 인터페이스를 만들어서 Car, Bike가 상속하게 해야할지 고민이네요. Vehicle이란 인터페이스가 가질 Method는 go(), stop() 등의 자동차가 하는 행위일 것 같은데 사실 매매용 소프트웨어이기 때문에 자동차가 하는 행위 자체를 선언하는 것은 별 쓸모가 없어보이고 매매 시스템이니깐 매매되는 자동차라는 점에 중점을 두면 Buyable이란 인터페이스를 만들어 isSold(), buy()등의 매매 관련 메소드를 정의하는게 좀더 좋은 선택으로 보입니다.
그럼 한번 Buyable이란 인터페이스를 정의해 보겠습니다. 알아둬야 할 사항으로 자바에서는 대개 OOP의 Polymorphism(다형성)을 지원하기 위해 Interface을 정의하고 이를 상속하는 기법을 사용합니다. 특정 인터페이스를 상속하는 몇몇 클래스들이 인터페이스에 선언된 메소드의 정의가 동일하다면 그 인터페이스를 상속하는 Abstract 클래스를 정의하고 이 Abstract 클래스를 다시 상속하는 기법이 널리 쓰입니다. 그런데 Java 8에서는 interface에 default method와 static method란게 도입되어서 이젠 그런 기법이 서버쪽에서는 안쓰일 것 같네요. 서버 개발에 대한 실무 경험이 없어 장담하긴 힘듭니다.;; 안드로이드는 아직 Java 7만 지원이 되어서 java 8은 사실 고려 안해도 되구요.
[Java 8 Interface의 default methods, static methods 관련 글은 여기로]
package com.jayjaylab.app.usedcar /** * 매매할 수 있는 객체를 나타냅니다. */ public interface Buyable { /** * 해당 상품이 다 팔렸는지 알기 위해 호출합니다. * @return true 이미 다 팔림, false 재고가 남아 있음. */ boolean isSoldOut(); /** * 구매할 때 호출합니다. * @param option 구매할 때 추가할 옵션들입니다. * @return true 구매 신청이 정상적으로 완료됨, false 구매 실패 */ boolean buy(Option option); ... }
package com.jayjaylab.app.usedcar public class Car implements Buyable { int drivingDistance; // in km(killo meters) String dateMadeAt; // in 2007-12-03T10:15:30 format int color; Engine engine; Wheel wheel; Manufacturer manufacturer; String model; Trunk trunk; Roof roof; // and so on... public boolean isSoldOut() { return false; } public boolean buy(Option option) { return true; } ... }
음, 위에 것처럼 구현하니 왠지 매매할 수 있을것 같은 자동차 Abtraction이 만들어진 것 같네요. 이번 글은 우선 여기까지하고 시간될 때 다시 돌아오도록 합죠.
'java' 카테고리의 다른 글
JAVA 8 Fuctional Inteface, Method reference and Lambda expression #2 (0) | 2016.05.04 |
---|---|
JAVA 8 Fuctional Inteface, Method reference and Lambda expression #1 (0) | 2016.04.30 |
benchmarking 코드를 작성해 보자 #1 (1) | 2016.03.15 |
추상화(Abstraction) 이해의 중요성 #2 (0) | 2016.03.06 |
추상화(Abstraction) 이해의 중요성 #1 (0) | 2016.03.02 |