데이터 체계화 - ChoDragon9/posts GitHub Wiki
데이터 체계화
데이터 연동에 있어서 직접/간접/단방향/양방향 등과 같은 내용을 다룬다.
필드 자체 캡슐화(Self Encapsulate Field)
필드에 직접 접근하던 중 그 필드로의 결합의 문제가 생길 때 읽기/쓰기 메서드를 작성해서 메서드를 통해서만 접근
// Before
class MyClass {
constructor () {
this._low = null
this._high = null
}
includes (arg) {
return arg >= this._low && arg <= this._high
}
}
// After
class MyClass {
constructor () {
this._low = null
this._high = null
}
includes (arg) {
return arg >= this.getLow() && arg <= this.getHigh()
}
getLow () { return this._low }
getHigh () { return this._high }
}
데이터 값을 객체로 전환(Replace Data Value with Object)
데이터 항목에 데이터나 기능을 더 추가해야 할 때
// Before
class Order {
constructor (customer) {
this.customer = customer
}
getCustomer () { return this.customer }
setCustomer (customer) { this.customer = customer }
}
// After
class Customer {
constructor (name) {
this.name = name
}
getName () { return this.name }
}
class Order {
constructor (customer) {
this.customer = new Customer(customer)
}
getCustomer () { return this.customer.getName() }
setCustomer (customer) {
this.customer = new Customer(customer)
}
}
값을 참조로 전환(Change Value to Reference)
클래스에 같은 인스턴스가 많이 들어 있어서 이것들을 하나의 객체로 바꿔야 할 때
// Before
class Customer {
constructor (name) {
this.name = name
}
getName () { return this.name }
}
class Order {
constructor (customer) {
this.customer = new Customer(customer)
}
getCustomer () { return this.customer.getName() }
setCustomer (customer) {
this.customer = new Customer(customer)
}
}
// After
class Customer {
constructor (name) {
this.name = name
}
getName () { return this.name }
static create (name) { // Factory Method
return new Customer(name)
}
}
class Order {
constructor (customer) {
this.customer = Customer.create(customer)
}
getCustomer () {
return this.customer.getName()
}
setCustomer (customer) {
this.customer = Customer.create(customer)
}
}
참조를 값으로 전환(Change Reference to Value)
참조 객체가 작고 수정할 수 없고 관리하기 힘들 때
배열을 객체로 전환(Replace Array with Object)
배열을 구성하는 특정 원소가 별의별 의미를 지닐 때 각 배열을 각 원소마다 필드가 하나씩 있는 객체로 전환한다.
배열은 흔히 데이터 정리에 사용되는 구조로 같은 비슷한 데이터 구조일 때만 사용하자.
// Before
const row = []
row[0] = "Liverpool"
row[1] = 15
// After
const row = new Performance()
row.setName("Liverpool")
row.setWins(15)
관측 데이터 복제(Duplicate Observed Data)
도메인 데이터는 GUI 컨트롤 안에서만 사용 가능한데, 도메인 메서드가 그 데이터에 접근해야 할 때(Observer Pattern)
클래스의 단방향 연결을 양방향으로 전환(Change Unidirectional Association to Bidirectional)
두 클래스가 서로의 기능을 사용해야 하는 데 한 방향으로만 연결되어 있을
클래스의 양방향 연결을 단방향으로 전환(Change Bidirectional Association to Unidirectional)
두 클래스가 양방향으로 연결되어 있는 데 한 클래스가 다른 클래스의 기능을 더 이상 사용하지 않게 되었을 때
마법 숫자를 기호 상수로 전환(Replace Magic Number with Symbolic Constant)
특수 의미를 지닌 리터럴 숫자가 있을 때 의미를 살린 이름의 상수를 작성한 후 리터럴 숫자를 그 상수로 교체하자
필드 캡슐화(Encapsulate Field)
public 필드가 있을 때 그 필드를 private로 만들고 필드용 읽기/쓰기 메서드를 작성하자
컬렉션 캡슐화(Encapsulate Collection)
메서드가 컬렉션을 반환할 때 그 메서드가 읽기 전용 뷰를 반환하게 수정하고 추가 메서드와 삭제 메서드를 작성하자
// Before
class Person {
constructor () {
this.set = new Set()
}
getCourses () {
return this.set
}
setCourses (courses) {
this.set = courses
}
}
// After
class Person {
constructor () {
this.set = new Set()
}
getCourses () {
return new Set(...this.set)
}
addCourses (course) {
this.set.add(course)
}
removeCourses (course) {
this.set.delete(course)
}
}
분류 부호를 하위클래스로 전환(Replace Type Code with Subclasses)
클래스 기능에 영향을 주는 변경불가 분류 부호가 있을 때 분류 부호를 하위 클래스로 만들자
// Before
class Employee {
constructor () {
this.ENGINEER = 9
this.SALESMAN = 4
this.type = 0
}
}
// After
class Employee {
constructor () { }
}
class Engineer extends Exployee {
constructor () { super() }
}
class Salesman extends Exployee {
constructor () { super() }
}
분류 부호를 상태/전략 패턴으로 전환(Replace Type Code with State/Strategy)
분류 부호가 클래스의 기능에 영향을 주지만 하위클래스로 전환할 수 없을 때 그 분류 부호를 상태 객체로 만들자
class Employee {
constructor () {
this.ENGINEER = 9
this.SALESMAN = 4
this.type = 0
}
}
// After
class Employee {
constructor () {
this.type = null
}
setType (type) {
this.type = EmployeeType.newType(type)
}
}
class EmployeeType {
static newType (type) {
switch (type) {
case 'ENGINEER':
return new Engineer()
case 'SALESMAN':
return new Salesman()
}
}
}
class Engineer {
constructor () { }
}
class Salesman {
constructor () { }
}
하위클래스를 필드로 전환(Replace Subclass with Fields)
여러 하위클래스가 상수 데이터를 반환하는 메서드만 다룰 때 각 하위 클래스의 메서드를 상위클래스 필드로 전환하고 하위클래스는 전부 삭제하자
// Before
class Person {
getCode () { }
}
class Male extends Person {
getCode () {
return 'M'
}
}
class Female extends Person {
getCode () {
return 'F'
}
}
// After
class Person {
constructor (isMale, code) {
this.code = code
this.isMale = isMale
}
static createMale () {
return new Person(true, 'M')
}
static createFemale () {
return new Person(false, 'F')
}
}