pro typescript.ch03.object orientation in typescript

46
Pro TypeScript Ch.03 Object Orientation in TypeScript 윤윤윤 ([email protected])

Upload: seok-joon-yun

Post on 15-Apr-2017

75 views

Category:

Software


1 download

TRANSCRIPT

Page 1: Pro typescript.ch03.Object Orientation in TypeScript

Pro TypeScriptCh.03 Object Orientation in Type-Script

윤석준 ([email protected])

Page 2: Pro typescript.ch03.Object Orientation in TypeScript

2

Agenda Object Orientation in TypeScript

SOLID Principles

Design Patterns

Mixins

Page 4: Pro typescript.ch03.Object Orientation in TypeScript

Object Orientation in TypeScript- Classes- Instance of

classes- Methods- Inheritance- Open Recur-

sion- Encapsulation- Delegation- Polymophism

https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)

https://en.wikipedia.org/wiki/This_(computer_programming)#Open_recursionhttps://en.wikipedia.org/wiki/Encapsulation_(computer_programming)

https://en.wikipedia.org/wiki/Delegation_(computing)

https://en.wikipedia.org/wiki/Polymorphism_(computer_science)

Ch.01

Page 5: Pro typescript.ch03.Object Orientation in TypeScript

5

Open Recursion

Combination of recursion and late binding 멤버 함수가 자기 자신을 호출시 서브클래스에 정의된 함수로 대체될 수 있음

이거 그냥 override 아니에요 ? No, no, no. Recursion and late binding.

그래도 그냥 함수 override 인데…

Page 6: Pro typescript.ch03.Object Orientation in TypeScript

6

ex. Open Recursioninterface FileItem { path: string; contents: string[];}class FileReader { getFiles(path: string, depth: number = 0) { var fileTree = []; var files = fs.readdirSync(path);

for (var i = 0; i < files.length; i++) { var file = files[i]; var stats = fs.statSync(file); var fileItem; if (stats.isDirectory()) { // Add directory and contents fileItem = { path: file, contents: this.getFiles(file, (depth + 1)) }; } else { // Add file fileItem = { path: file, contents: [] }; } fileTree.push(fileItem); } return fileTree; }}

class LimitedFileReader extends FileReader { constructor(public maxDepth: number) { super(); } getFiles(path: string, depth = 0) { if (depth > this.maxDepth) { return []; } return super.getFiles(path, depth); }}

// instatiating an instance of LimitedFileReadervar fileReader = new LimitedFileReader(1);

// results in only the top level, and one additional level being readvar files = fileReader.getFiles('path');

Page 7: Pro typescript.ch03.Object Orientation in TypeScript

7

Encapsulation

Private 제한자를 사용해 변수 , 함수를 외부로부터 숨김 외부에 알리고 싶지 않은 것을 숨길 수 있음

외부에서 몰라도 되는 것을 숨기는 것은 추상화 (Abstraction)

추상화나 캡슐화나… 내가 보기엔 다 거서 건데…

Page 8: Pro typescript.ch03.Object Orientation in TypeScript

8

ex. Encapsulationclass Totalizer { private total = 0; private taxRateFactor = 0.2;  addDonation(amount: number) { if (amount <= 0) { throw new Error('Donation exception'); } var taxRebate = amount * this.taxRateFactor; var totalDonation = amount + taxRebate; this.total += totalDonation; }  getAmountRaised() { return this.total; }} var totalizer = new Totalizer();totalizer.addDonation(100.00); var fundsRaised = totalizer.getAmountRaised(); // 120console.log(fundsRaised);

Page 9: Pro typescript.ch03.Object Orientation in TypeScript

9

Delegation

Wrapper class 로 원래 class 를 감싸는 형태 상속관계 (is a) 가 아닌 경우의 좋은 대안

코드 재사용성 측면에 있어서 가장 유용한 개념

Page 10: Pro typescript.ch03.Object Orientation in TypeScript

10

Delegation vs Inheritance Delegation : Has

A

Ingeritance : Is

A

Page 11: Pro typescript.ch03.Object Orientation in TypeScript

11

ex. Delegationinterface ControlPanel { startAlarm(message: string): any;} interface Sensor { check(): any;} class MasterControlPanel { private sensors: Sensor[] = []; constructor() { // Instantiating the delegate HeatSensor this.sensors.push(new HeatSensor(this)); }  start() { for (var i= 0; i < this.sensors.length; i++) { // Calling the delegate this.sensors[i].check(); } window.setTimeout(() => this.start(), 1000); }  startAlarm(message: string) { console.log('Alarm! ' + message); }}

class HeatSensor { private upperLimit = 38; private sensor = { read: function() { return Math.floor(Math.random() * 100); } };  constructor(private controlPanel: ControlPanel) { }  check() { if (this.sensor.read() > this.upperLimit) { // Calling back to the wrapper this.controlPanel.startAlarm('Overheating!'); } }} var cp = new MasterControlPanel();

cp.start();

Page 12: Pro typescript.ch03.Object Orientation in TypeScript

12

Polymorphism

같은 함수 시그너쳐를 여러가지로 다르게 구현 An interface implemented by many classes An interface implemented by many objects An interface implemented by many functions A superclass with a number of specialized sub-classes

Any structure with many similar structures

Page 13: Pro typescript.ch03.Object Orientation in TypeScript

13

ex. Polymorphisminterface Vehicle { moveTo(x: number, y: number);} class Car implements Vehicle { moveTo(x: number, y: number) { console.log('Driving to ' + x + ' ' + y); }} class SportsCar extends Car {} class Airplane { moveTo(x: number, y: number) { console.log('Flying to ' + x + ' ' + y); }} function navigate(vehicle: Vehicle) { vehicle.moveTo(59.9436499, 10.7167959);} var airplane = new Airplane();navigate(airplane);var car = new SportsCar();navigate(car);

Page 14: Pro typescript.ch03.Object Orientation in TypeScript

SOLID Principles

Page 15: Pro typescript.ch03.Object Orientation in TypeScript

15

SOLID Principle S : Single responsibility principle

O : Open/Closed principle

L : Liskov substitution principle

I : Interface segregation principle

D : Dependency inversion principle

Page 16: Pro typescript.ch03.Object Orientation in TypeScript

16

Single responsibility princi-ple

관련성이 있는 코드들을 클래스 , 모듈에 모아야 함 . 함우의 경우에도 한 가지 일만 수행해도록 나눠야 함 . (Uncle Bob : http://blog.cleancoder.com

)

작업하다보면 SRP 기준에 부합하는지 어긋나는지 나누기가 애매한 경우가 많음

단일 책임의 원칙

클래스는 오직 한가지 작업만 수행해야 하며 ,한 가지 이유에 의해서만 변경되어야 함 .

Page 17: Pro typescript.ch03.Object Orientation in TypeScript

17

ex. Single responsibility principle (SRP) vio-lationclass Movie { private db: DataBase; constructor(private title: string, private year: number) { this.db = DataBase.connect('user:pw@mydb', ['movies']); } getTitle() { return this.title + ' (' + this.year + ')'; } save() { this.db.movies.save({ title: this.title, year: this.year }); }}

Page 18: Pro typescript.ch03.Object Orientation in TypeScript

18

ex. Separate reasons for changeclass Movie { constructor(private title: string, private year: number) { } getTitle() { return this.title + ' (' + this.year + ')'; }} class MovieRepository { private db: DataBase; constructor() { this.db = DataBase.connect('user:pw@mydb', ['movies']); } save(movie: Movie) { this.db.movies.save(JSON.stringify(movie)); }} // Movievar movie = new Movie('The Internship', 2013);// MovieRepositoryvar movieRepository = new MovieRepository();

movieRepository.save(movie);

Page 19: Pro typescript.ch03.Object Orientation in TypeScript

19

Open/closed principle

변경가능성을 염두해 두고 적응형 코드로 작성을 하되 , 변경 사항에 대해서는 기존 코드를 수정할 필요 없게 만들어야 한다 .

개방 / 폐쇄 원칙확장에 대해서는 개방적이어여 하고 ,수정에 대해서는 폐쇄적이어야 한다 .

Page 20: Pro typescript.ch03.Object Orientation in TypeScript

20

ex. Open–closed principle (OCP)class RewardPointsCalculator { getPoints(transactionValue: number) { // 4 points per whole dollar spent return Math.floor(transactionValue) * 4; }} class DoublePointsCalculator extends RewardPointsCalculator { getPoints(transactionValue: number) { var standardPoints = super.getPoints(transactionValue); return standardPoints * 2; }} var pointsCalculator = new DoublePointsCalculator(); alert(pointsCalculator.getPoints(100.99));

Page 21: Pro typescript.ch03.Object Orientation in TypeScript

21

The Liskov Substitution Prin-ciple

개체 타입을 검사해서 진행되는 코드의 경우 LSP 를 위반할 가능성이 높음

완벽하게 대체 가능하게 하기 위해서 고려해야할 사항

( 멤버의 제한자 , 함수의 인자 타입 , 함수의 리턴 타입 , 오류 발생시 예외 타입 )

리스코프 치환 원칙

S 가 T 의 하위속성이라면 프로그램의 변경없이T 의 객체를 S 로 교체 ( 치환 ) 할 수 있어야 한다 .

Data Abstraction and Hireachy, 1998 - Babara Liskov

Page 22: Pro typescript.ch03.Object Orientation in TypeScript

22

The Liskov Substitution Prin-ciple 계약 규칙

서브타입에서 더 강력한 사전 조건을 정의할 수 없다 . 서브타입에서 더 완화된 사후 조건을 정의할 수 없다 . 슈퍼타입의 불변식 ( 항상 탐으로 유지되는 조건들 ) 은 서브타입에서도 반드시 유지되어야 한다 .

가변성 규칙 서브타입의 메서드 인수는 반 공변성 (contravariance) 을 가져야 한다 . 서브타입의 리턴 타입은 공변성 (variance) 을 가져야 한다 . 서브타입은 슈퍼타입이 발생시크는 것돠 동일한 타입의 예외나

그 서브타입이나 슈퍼타입만 사용해야 한다 .

출처 : C# 으로 배우는 적응형 코드

Page 23: Pro typescript.ch03.Object Orientation in TypeScript

23

The Interface Segregation Principle

클래스가 인터페이스 구현시 필요하지 않은 기능에 대해서 구현할 필요가 없어야 함

이미 구현된 인터페이스에 새로운 기능을 추가할 경우 기존에 해당 인터페이스를

구현한 클래스들을 모두 수정해야 함

인터페이스 분리 원칙

인터페이스를 최대한 작게 만드는 것이여러가지 기능을 하는 인터페이스 하나보다 더 좋다 .

Page 24: Pro typescript.ch03.Object Orientation in TypeScript

24

ex. Printer interface

interface Printer { copyDocument(); printDocument(document: Document); stapleDocument(document: Document, tray: number);}

interface Printer { printDocument(document: Document);}interface Stapler { stapleDocument(document: Document, tray: number);}interface Copier { copyDocument();}class SimplePrinter implements Printer { printDocument(document: Document) { //... }}class SuperPrinter implements Printer, Stapler, Copier { printDocument(document: Document) { //... } copyDocument() { //... } stapleDocument(document: Document, tray: number) { //... }}

Page 25: Pro typescript.ch03.Object Orientation in TypeScript

25

The Dependency Inversion Principle

컴퍼넌트들 끼리 강하게 결합되어 있는 경우 수정이 힘듬

이미 구현된 클래스들 조차 재사용성이 힘들어짐

의존성 역주입 원칙

직접적인 의존을 피하고 ,인터페이스에 의존하라 .

Page 26: Pro typescript.ch03.Object Orientation in TypeScript

26

ex. High-level dependency on low-level class class LightSwitch { private isOn = false; constructor(private light: Light) { } onPress() { if (this.isOn) { this.light.switchOff(); this.isOn = false; } else { this.light.switchOn(); this.isOn = true; } }}

interface LightSource { switchOn(); switchOff();} class Light { switchOn() { //... } switchOff() { //... }}

Page 27: Pro typescript.ch03.Object Orientation in TypeScript

Design Pattern

Page 28: Pro typescript.ch03.Object Orientation in TypeScript

28

Design Pattern 이미 알려진 문제에 대해 해결책을 디자인을 통해서 해결

GoF(gang of four) 의 Design Patterns 가 가장 유명함

(23 가지 패턴 )

Diaz and Harmes 의 Pro JavaScript Design Patterns 가 있음

Strategy Pattern, Abstract Factory Pattern 만 알아보겠음

Page 29: Pro typescript.ch03.Object Orientation in TypeScript

29

The Strategy Pattern

알고리즘을 캡슐화

런타임에 인터페이스를 구현한 알고리즘을 제공

전략 패턴

Page 30: Pro typescript.ch03.Object Orientation in TypeScript

30

The Abstract Factory Pattern

Factory Pattern : 객체를 직접 생성하지 않고 , Factory 를 통해서 생성

Abstract Factory : Factory 를 추상화 . 인터페이스로 구현한 Factory 를 런타임에

전달

추상 팩토리 패턴

Page 31: Pro typescript.ch03.Object Orientation in TypeScript

31

ex. Wheel cleaning and BodyCleaninginterface WheelCleaning { cleanWheels(): void;} class BasicWheelCleaning implements WheelCleaning { cleanWheels() { console.log('Soaping Wheel'); console.log('Brushing wheel'); }} class ExecutiveWheelCleaning extends BasicWheelCleaning { cleanWheels() { super.cleanWheels(); console.log('Waxing Wheel'); console.log('Rinsing Wheel'); }}

interface BodyCleaning { cleanBody(): void;} class BasicBodyCleaning implements BodyCleaning { cleanBody() { console.log('Soaping car'); console.log('Rinsing Car'); }} class ExecutiveBodyCleaning extends BasicBodyCleaning { cleanBody() { super.cleanBody(); console.log('Waxing car'); console.log('Blow drying car'); }}

Page 32: Pro typescript.ch03.Object Orientation in TypeScript

32

ex. CarWashProgram class before the ab-stract factory patternclass CarWashProgram {

constructor(private washLevel: number) { } runWash() { var wheelWash: WheelCleaning; var bodyWash: BodyCleaning; switch (this.washLevel) { case 1: wheelWash = new BasicWheelCleaning(); wheelWash.cleanWheels(); bodyWash = new BasicBodyCleaning(); bodyWash.cleanBody(); break; case 2: wheelWash = new BasicWheelCleaning(); wheelWash.cleanWheels(); bodyWash = new ExecutiveBodyCleaning(); bodyWash.cleanBody(); break;

case 3: wheelWash = new ExecutiveWheelCleaning(); wheelWash.cleanWheels(); bodyWash = new ExecutiveBodyCleaning(); bodyWash.cleanBody(); break; } }}

Page 33: Pro typescript.ch03.Object Orientation in TypeScript

33

ex. Abstract factory and Concrete factories

interface ValetFactory { getWheelCleaning() : WheelCleaning; getBodyCleaning() : BodyCleaning;}

 class SilverWashFactory implements ValetFactory { getWheelCleaning() { return new BasicWheelCleaning(); } getBodyCleaning() { return new ExecutiveBodyCleaning(); }} class GoldWashFactory implements ValetFactory { getWheelCleaning() { return new ExecutiveWheelCleaning(); } getBodyCleaning() { return new ExecutiveBodyCleaning(); }}

class BronzeWashFactory implements ValetFactory { getWheelCleaning() { return new BasicWheelCleaning(); } getBodyCleaning() { return new BasicBodyCleaning(); }}

Page 34: Pro typescript.ch03.Object Orientation in TypeScript

34

ex. Abstract factory pattern in use

class CarWashProgram { constructor(private cleaningFactory: ValetFactory) { } runWash() { var wheelWash = this.cleaningFactory.getWheelCleaning(); wheelWash.cleanWheels(); var bodyWash = this.cleaningFactory.getBodyCleaning(); bodyWash.cleanBody(); }}

Page 35: Pro typescript.ch03.Object Orientation in TypeScript

MixinsSteve’s Ice Cream in Somerville, Massachusetts.

Page 36: Pro typescript.ch03.Object Orientation in TypeScript

36

TypeScript Mixins

step 1. 클래스 내의 mix-in 함수를 선언

step 2. Augumented class ( 증강 클래스 ) 를 implements 로

전달받음

(extends 가 아님 )step 3. 일반 클래스와 똑같이 해당 함수를 사용

Page 37: Pro typescript.ch03.Object Orientation in TypeScript

37

ex. Mixin enabler function

function applyMixins(derivedCtor: any, baseCtors: any[]) { baseCtors.forEach(baseCtor => { Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => { if (name !== 'constructor') { derivedCtor.prototype[name] = baseCtor.prototype[name]; } }) });}

Page 38: Pro typescript.ch03.Object Orientation in TypeScript

38

ex. Reusable classesclass Sings { sing() { console.log('Singing'); }} class Dances { dance() { console.log('Dancing'); }} class Acts { act() { console.log('Acting'); }}

Page 39: Pro typescript.ch03.Object Orientation in TypeScript

39

ex. Composing classesclass Actor implements Acts { act: () => void;} applyMixins(Actor, [Acts]); class AllRounder implements Acts, Dances, Sings { act: () => void; dance: () => void; sing: () => void;} applyMixins(AllRounder, [Acts, Dances, Sings]);

Page 40: Pro typescript.ch03.Object Orientation in TypeScript

40

ex. Using the classes

var actor = new Actor();actor.act(); var allRounder = new AllRounder();allRounder.act();allRounder.dance();allRounder.sing();

Page 41: Pro typescript.ch03.Object Orientation in TypeScript

41

When to use Mixins 상속 (is a) 도… ..

위임 (has a) 도……

안될 때 !!! -> 믹스인 (can do)

추가 옵션을 가질 수 있는 클래스 ( 믹스인 함수 )

여러 클래스에서 동일한 함수를 재사용

비슷한 기능들의 조합으로 여러 클래스를 생성

Page 42: Pro typescript.ch03.Object Orientation in TypeScript

42

Restrictions of Mixins 믹스인 함수를 private 으로 선언하면 안됨

증강 클래스의 함수를 private 로 선언하면 안됨

증강 클래스의 변수는 매핑 안됨 디폴트 값을 정의하지 않는 것이 좋음

개체 별로 종속되지 않는 경우에는 static 으로 선언하는 방법도 고려

개체 별로 다른 값이 필요한 경우 믹스인 함수에서 초기화가 필요

Page 43: Pro typescript.ch03.Object Orientation in TypeScript

43

ex. Properties not mappedclass Acts { public message = 'Acting'; act() { console.log(this.message); }} class Actor implements Acts { public message: string; act: () => void;} applyMixins(Actor, [Acts]); var actor = new Actor(); // Logs 'undefined', not 'Acting'actor.act();

class Acts { public static message = 'Acting'; act() { alert(Acts.message); }}

Page 44: Pro typescript.ch03.Object Orientation in TypeScript

Summary

Page 45: Pro typescript.ch03.Object Orientation in TypeScript

45

Summary

TypeScript 는 객체지향적인 특징들을 대부분 포함하고 있습니다 .

SOLID 이론은 코드가 계속 유지될 수 있도록 해주는 것을 그 목표로 하고 있습니다 .

디자인 패턴은 일반적으로 알려진 문제들에 대한 해법이 될 수 있습니다 .

믹스인은 각각의 요소들을 대체할 수 있는 방법을 제공합니다 .