// 자료 구조
public interface Vehicle {
double getFuelTankCapacityInGallons(); // 연료탱크 용량(갤런 단위)
double getGallonsOfGasoline(); // 가솔린 (갤런 단위)
}
public class Car implements Vehicle {
double fuelTankCapacitInGallons;
double gallonsOfGasoline;
public double getFuelTankCapacityInGallons() {
return this.fuelTankCapacitInGallons;
}
public double getFuelTankCapacityInGallons() {
return this.gallonsOfGasoline;
}
}
비지니스 로직 없이 순수 데이터를 저장하는 자료구조의 역할이다.
// 객체
public interface Vehicle {
double getPercentFuelRemain();
}
public class Car implements Vehicle {
private double fuelTankCapacitInGallons;
private double gallonsOfGasoline;
public Car(double fuelTankCapacitInGallons, double gallonsOfGasoline) {
if (fuelTankCapcitInGallons <= 0) {
throw new IllegalArgumentException("fuelTankCapacitInGallons must be greater than zero");
}
this.fuelTankCapacitInGallons = fuelTankCapacitInGallons;
this.gallonsOfGasoline = gallonsOfGasoline;
}
public double getPercentFuelRemain() {
return this.gallonsOfGasoline / this.fuelTankCapacitInGallons * 100;
}
}
위의 코드는 생성자에 비즈니스 로직과 관련된 코드가 들어가 있고, 필드를 private 으로 하여 자료를 숨겼다.
public class Square {
public Point topLeft;
public double side;
}
public class Rectangle {
public Point topLeft;
public double height;
public double width;
}
public class Circle {
public Point center;
public double radius;
}
public class Geometry {
public final double PI = 3.141592653589793;
public double area(Object shape) throws NoSuchShapeException {
if (shape instanceof Square) {
Shape s = (Square)shape;
return s.side * s.side;
} else if (shape instanceof Rectangle) {
Rectangle r = (Rectangle)shape;
return r.height * r.width;
} else if(shape instanceof Circle) {
Circle c = (Circle)shape;
return PI * c.radius * c.radius;
}
throw new NoSuchShapeException();
}
}
만약 Triangle 이라는 새로운 클래스(자료구조가) 추가된다면? area() 함수 안에 if-else 문을 수정해야 한다.
public class Square implements Shape {
private Point topLeft;
private double side;
public double area() {
return side * side;
}
}
public class Rectangle implements Shape {
private Point topLeft;
private double height;
private double width;
public double area() {
return height * width;
}
}
public class Circle implements Shape {
private Point center;
private double radius;
public final double PI = 3.141592653589793;
public double area() {
return PI * radius * radius;
}
}
만약 Triangle 이라는 클래스를 추가한다면?
Triangle 클래스를 생성 후 Shape 인터페이스를 상속 받은 후area() 함수를 오버라이딩 하면된다.
즉 객체지향 코드는 새로운 클래스를 추가하기가 쉽다. 하지만 함수를 추가해야 한다.
A a = new A(); B b = a.getB() (O) C c = a.getB().getC(); (X)
// 객체 - 기차 충돌. 디미터의 법칙 위배
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
// 자료구조 - OK
final String outputDir = ctxt.options.scratchDir.absolutePath;
// 객체에 대한 해결책이 아니다. getter를 통했을 뿐, 값을 가져오는 것은 자료구조이다.
ctxt.getAbsolutePathOfScratchDirectoryOption();
ctxt.getScratchDirectoryOption().getAbsolutePath();
// 왜 절대 경로를 가져올까.. 근본 원인을 생각해보자!
// 객체는 자료를 숨기고 자료를 다루는 함수만 공개한다.
BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);
로직 없이 필드만 갖는다.
일반적으로 클래스명이 Dto(or DTO)로 끝난다.
getter/setter 를 갖기도 한다.
- Beans
Java Beans: 데이터 표현이 목적인 자바 객체
멤버 변수는 private 속성이다.
getter와 setter를 가진다.
public class AddressDto {
private String street;
private String zip;
}
public AddressDto(String street, String zip) {
this.street = street;
this.zip = zip;
}
public String getStreet() {
return street;
}
public String setStreet(String street) {
this.street = street;
}
public String getZip() {
return zip;
}
public String setZip(String zip) {
this.zip = zip;
}
public class Employee enxtends ActiveRecord {
private String name;
private String address;
...
}
// ----
Employee bob = Employee.findByName("Bob Martin");
bob.setName("Robert C. Martin");
bob.save();
해당 포스팅은 제로 베이스 클린코드 한달한권을 수강 후 정리한 내용입니다.