TypeScript로 객체 지향 실천 그 ①

오브젝트 지향 설계 실천 가이드~Ruby로 아는 진화 계속하는 유연한 어플리케이션의 기르는 방법
을 읽고 있으므로 메모가 엄청나게 정리해 본다.

Ruby가 아닌 TypeScript로 구현해 보았다.

모델





1. 변수 숨기기



변수를 private로 해, 외부로부터의 취득은 getter로 한다. 이것에 의해 직접 변수가 괴롭히는 것을 막는 것과, 프라이빗 변수에 추가로 1.2배 계수를 곱하고 싶은 등의 요망이 있었을 때는 getter내를 만지기만 하면 된다.

Gear1.ts

export class Gear {

    private PI = 3.14;
    constructor(private _chainring: number, private _cog: number,private _rim: number, private _tire: number) {
    }

    get rim() {
        return this._rim;
    }

    get tire() {
        return this._tire;
    }

    get cog(): number {
        return this._cog;
    }

    get chainring() {
        return this._chainring;

    }

    diameter() {
        return this.rim + this.tire * 2;
    }

    public ratio(): number {
        return this.chainring / this.cog
    }

    public gearInches() {
            return this.ratio() * this.diameter();
    }
}


2. 종속성을 클래스로 나누기



1의 클래스에서는 기어(Gear)에 관한 메소드에 바퀴(Wheel)에 대한 정보(rim, tire)까지도 포함되어 있었다. 이것은 단일 책임의 원칙 (SRP)의 위반하고 확장 성을 위해 분리 시 두는 것이 좋다.

Gear2.ts
import { Wheel } from "./Wheel";


class Gear {
    constructor(private _chainring: number, private _cog: number, private wheel?: Wheel) {
    }

    get cog(): number {
        return this._cog;
    }

    get chainring() {
        return this._chainring;

    }

    public ratio(): number {
        return this.chainring / this.cog
    }

    public gearInches() {
        if (this.wheel) {
            return this.ratio() * this.wheel.diameter();
        }
        return null;
    }
}




Wheel.ts
export class Wheel {
    private PI = 3.14;

    constructor(private _rim: number, private _tire: number) {
    }

    get rim() {
        return this._rim;
    }

    get tire() {
        return this._tire;
    }

    diameter() {
        return this.rim + this.tire * 2;
    }

    cicle() {
        return this.diameter() * this.PI;
    }
}


3. 인수를 해시로 만들기



위까지는 인수의 순서를 모르고는 제대로 클래스를 사용할 수 없었다. 그 때문에, 인수로서 알기 쉽게 파라미터를 부여하기로 한다.

Gear3.ts
import { Wheel } from "./Wheel";

export class Gear {
    private readonly _chainring:number;
    private readonly _cog: number;
    private readonly wheel?: Wheel;

    constructor(args: any) {
        this._chainring = args['chainring']
        this._cog = args['cog']
        this.wheel = args['wheel']
    }

    get cog(): number {
        return this._cog;
    }

    get chainring() {
        return this._chainring;

    }

    public ratio(): number {
        return this.chainring / this.cog
    }

    public gearInches() {
        if (this.wheel) {
            return this.ratio() * this.wheel.diameter();
        }
        return null;
    }
}


이 클래스를 사용하는 방법은 다음과 같습니다.
const args = {
    chainring: 10,
    cog:10,
    wheel: new Wheel(10,10)
}
const gear = new Gear(args);

console.log(gear.gearInches()) // => 30


3.Factory 클래스



외부의 클래스 등 스스로 괴롭히지 않는 경우, 인수의 순서를 바꾸거나 해시(JSON 형식)로 할 수 없기 때문에, Factory 클래스로 랩 하는 것으로 해결한다.

GearFactory.ts
import { Wheel } from "./Wheel";

class GearFactory {

    constructor(private args:any) {
    }
    gear(): Gear{
        return new Gear(this.args['chainring'],this.args['cog'],this.args['wheel'])
    }
}

export class Gear {
    constructor(private _chainring: number, private _cog: number, private wheel?: Wheel) {
    }

    get cog(): number {
        return this._cog;
    }

    get chainring() {
        return this._chainring;

    }

    public ratio(): number {
        return this.chainring / this.cog
    }

    public gearInches() {
        if (this.wheel) {
            return this.ratio() * this.wheel.diameter();
        }
        return null;
    }
}

const args = {
    chainring: 10,
    cog:10,
    wheel: new Wheel(10,10)
}
const gear = new GearFactory(args).gear();

console.log(gear.gearInches()); //=> 30


지금까지 이상! !



아직 도입이므로 오브젝트 지향이라고 하는 것보다 리팩토링같은데, 향후 오브젝트 지향 실천이 될 것인가! ! !

좋은 웹페이지 즐겨찾기