Last active
March 12, 2018 05:18
-
-
Save adhrinae/39c53a112f6f6ab21c0dd56c107da384 to your computer and use it in GitHub Desktop.
Mastering Javascript Design Pattern Chapter 04
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface Ship { | |
SetRudderAngleTo(angle: number); | |
SetSailConfiguration(configuration: SailConfiguration); | |
SetSailAngle(SailId: number, sailAngle: number); | |
GetCurrentBearing(): number; | |
GetCurrentSpeedEstimate(): number; | |
ShiftCrewWeightTo(weightToShift: number, locationId: number); | |
} | |
interface SailConfiguration { | |
crews: number; | |
foods: number; | |
} | |
interface SimpleShip { | |
TurnLeft(); | |
TurnRight(); | |
GoFoward(); | |
} | |
// 예제 코드의 구현방법이 잘못되었다고 느끼는 부분이 있는데, | |
// Apater에 사용할 Ship을 주입받지 않고 외부에 글로벌 변수에서 참고한다는 점이다. | |
class ShipAdater implements SimpleShip { | |
private ship: Ship; | |
constructor(ship: Ship) { | |
this.ship = ship; | |
} | |
TurnLeft() { | |
this.ship.SetRudderAngleTo(-30); | |
this.ship.SetSailAngle(3, 12); | |
} | |
TurnRight() { | |
this.ship.SetRudderAngleTo(30); | |
this.ship.SetSailAngle(5, -9); | |
} | |
GoFoward() { | |
this.ship.SetRudderAngleTo(0); | |
this.ship.SetSailAngle(0, 0); | |
this.ship.GetCurrentSpeedEstimate(); | |
} | |
} | |
// 메서드의 구현부는 생략 | |
class Boat implements Ship { | |
SetRudderAngleTo(angle: number) { | |
throw new Error("Method not implemented."); | |
} | |
SetSailConfiguration(configuration: SailConfiguration) { | |
throw new Error("Method not implemented."); | |
} | |
SetSailAngle(SailId: number, sailAngle: number) { | |
throw new Error("Method not implemented."); | |
} | |
GetCurrentBearing(): number { | |
throw new Error("Method not implemented."); | |
} | |
GetCurrentSpeedEstimate(): number { | |
throw new Error("Method not implemented."); | |
} | |
ShiftCrewWeightTo(weightToShift: number, locationId: number) { | |
throw new Error("Method not implemented."); | |
} | |
} | |
const ship = new ShipAdater(new Boat); | |
ship.GoFoward(); | |
ship.TurnLeft(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Religion { | |
export interface God { | |
prayTo(withSomething?: Sacrifice | HumanSacrifice | PrayerPurpose): void; | |
} | |
export class OldGods implements God { | |
prayTo(sacrifice: Sacrifice) { | |
console.log('We Old Gods hear your prayer'); | |
} | |
} | |
export class DrownedGod { | |
prayTo(humanSacrifice: HumanSacrifice) { | |
console.log('*BUBBLE* GURGLE'); | |
} | |
} | |
export class SevenGods { | |
prayTo(prayerPurpose: PrayerPurpose) { | |
console.log( | |
'Sorry there are a lot of us, it gets confusing here. Did you pray for something?' | |
); | |
} | |
} | |
class Sacrifice {} | |
class HumanSacrifice {} | |
class PrayerPurpose {} | |
export class PrayerPurposeProvider { | |
GetPurpose() { | |
return new PrayerPurpose(); | |
} | |
} | |
export class OldGodsAdapter { | |
constructor(private oldGoods: OldGods) {} | |
prayTo() { | |
const sacrifice = new Sacrifice(); | |
this.oldGoods.prayTo(sacrifice); | |
} | |
} | |
export class DrownedGodAdapter { | |
constructor(private drownedGod: DrownedGod) {} | |
prayTo() { | |
const sacrifice = new HumanSacrifice(); | |
this.drownedGod.prayTo(sacrifice); | |
} | |
} | |
export class SevenGodsAdapter { | |
constructor( | |
private sevenGods: SevenGods, | |
private prayerPurposeProvider: PrayerPurposeProvider | |
) {} | |
prayTo() { | |
this.sevenGods.prayTo(this.prayerPurposeProvider.GetPurpose()); | |
} | |
} | |
} | |
const god1 = new Religion.SevenGodsAdapter( | |
new Religion.SevenGods(), | |
new Religion.PrayerPurposeProvider() | |
); | |
const god2 = new Religion.DrownedGodAdapter(new Religion.DrownedGod()); | |
const god3 = new Religion.OldGodsAdapter(new Religion.OldGods()); | |
const gods: Religion.God[] = [god1, god2, god3]; | |
for (const god of gods) { | |
god.prayTo(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Composite { | |
interface IMenuComponent { | |
render(parentElement: HTMLElement): void; | |
} | |
interface IMenuItem extends IMenuComponent {} | |
interface IMenu extends IMenuComponent { | |
children: IMenuComponent[]; | |
} | |
class MenuItemLink implements IMenuItem { | |
constructor(public displayName: string, public url: string) {} | |
render(parentElement: HTMLElement) { | |
const link: HTMLAnchorElement = document.createElement('a'); | |
link.textContent = this.displayName; | |
link.href = this.url; | |
parentElement.appendChild(link); | |
} | |
} | |
class MenuItemImageLink implements IMenuItem { | |
constructor( | |
public displayName: string, | |
public url: string, | |
public imageUrl: string | |
) {} | |
render(parentElement: HTMLElement) { | |
const link: HTMLAnchorElement = document.createElement('a'); | |
link.href = this.url; | |
const img: HTMLImageElement = document.createElement('img'); | |
img.src = this.imageUrl; | |
link.appendChild(img); | |
const text = document.createTextNode(this.displayName); | |
link.appendChild(text); | |
parentElement.appendChild(link); | |
} | |
} | |
class Menu implements IMenu { | |
public children: IMenuComponent[] = []; | |
constructor(public displayName?: string) {} | |
render(parentElement: HTMLElement) { | |
if (this.displayName) { | |
parentElement.appendChild(document.createTextNode(this.displayName)); | |
} | |
const ul: HTMLUListElement = document.createElement('ul'); | |
this.children.forEach(child => { | |
const li: HTMLLIElement = document.createElement('li'); | |
child.render(li); | |
ul.appendChild(li); | |
}); | |
parentElement.appendChild(ul); | |
} | |
} | |
window.addEventListener('load', function() { | |
const menu: IMenu = new Menu(); | |
for (var i = 1; i <= 3; i++) { | |
menu.children.push(new MenuItemLink('Link ' + i, '?id=' + i)); | |
} | |
menu.children.push( | |
new MenuItemImageLink( | |
'Contact', | |
'mailto:info@sample.com', | |
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAITSURBVBgZpcHLThNhGIDh9/vn7/RApwc5VCmFWBPi1mvwAlx7BW69Afeu3bozcSE7E02ILjCRhRrds8AEbKVS2gIdSjvTmf+TYqLu+zyiqszDMCf75PnnnVwhuNcLpwsXk8Q4BYeSOsWpkqrinJI6JXVK6lSRdDq9PO+19vb37XK13Hj0YLMUTVVyWY//Cf8IVwQEGEeJN47S1YdPo4npDpNmnDh5udOh1YsZRcph39EaONpnjs65oxsqvZEyTaHdj3n2psPpKDLBcuOOGUWpZDOG+q0S7751ObuYUisJGQ98T/Ct4Fuo5IX+MGZr95jKjRKLlSxXxFxOEmaaN4us1Upsf+1yGk5ZKhp8C74H5ZwwCGO2drssLZZo1ouIcs2MJikz1oPmapHlaoFXH1oMwphyTghyQj+MefG+RblcoLlaJG/5y4zGCTMikEwTctaxXq/w9kuXdm9Cuzfh9acujXqFwE8xmuBb/hCwl1GKAnGccDwIadQCfD9DZ5Dj494QA2w2qtQW84wmMZ1eyFI1QBVQwV5GiaZOpdsPaSwH5HMZULi9UmB9pYAAouBQbMHHrgQcnQwZV/KgTu1o8PMgipONu2t5KeaNiEkxgAiICDMCCFeEK5aNauAOfoXx8KR9ZOOLk8P7j7er2WBhwWY9sdbDeIJnwBjBWBBAhGsCmiZxPD4/7Z98b/0QVWUehjkZ5vQb/Un5e/DIsVsAAAAASUVORK5CYII=' | |
) | |
); | |
const subMenu: IMenu = new Menu('Sub Menu'); | |
for (var i = 1; i <= 2; i++) { | |
subMenu.children.push(new MenuItemLink('Sub Link ' + i, '?id=' + i)); | |
} | |
menu.children.push(subMenu); | |
const contentDiv = document.getElementById('output'); | |
menu.render(contentDiv); | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface IArmor { | |
calculateDamageFromHit(hit: IHit); | |
getArmorIntegrity(): number; | |
} | |
interface IHit { | |
location: string; | |
weapon: string; | |
strength: number; | |
} | |
class BasicArmor implements IArmor { | |
constructor(private baseArmorPoint: number = 1) {} | |
calculateDamageFromHit(hit: IHit) { | |
console.log(`You got damage in ${hit.location} by ${hit.weapon}`); | |
return this.baseArmorPoint * hit.strength; | |
} | |
getArmorIntegrity() { | |
return this.baseArmorPoint; | |
} | |
} | |
class ChainMail implements IArmor { | |
constructor(private decoratedArmor: IArmor) {} | |
calculateDamageFromHit(hit: IHit) { | |
const reducedHit = { | |
...hit, | |
strength: hit.strength * 0.8, | |
}; | |
return this.decoratedArmor.calculateDamageFromHit(reducedHit); | |
} | |
getArmorIntegrity() { | |
return 0.9 * this.decoratedArmor.getArmorIntegrity(); | |
} | |
} | |
const armor = new ChainMail(new BasicArmor()); | |
console.log( | |
armor.calculateDamageFromHit({ | |
location: 'head', | |
weapon: 'Long Sword', | |
strength: 12, | |
}) | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class BlurayPlayer { | |
on() { | |
console.log('Bluray player turning on...'); | |
} | |
turnOff() { | |
console.log('Bluray player turning off...'); | |
} | |
play() { | |
console.log('Playing bluray disc...'); | |
} | |
} | |
class Amplifier { | |
on() { | |
console.log('Amplifier is turning on...'); | |
} | |
turnOff() { | |
console.log('Amplifier turning off...'); | |
} | |
setSource(source: string) { | |
console.log(`Setting source to ${source}`); | |
} | |
setVolume(volumeLevel: number) { | |
console.log(`Setting volume to ${volumeLevel}`); | |
} | |
} | |
class Lights { | |
dim() { | |
console.log('Lights are dimming...'); | |
} | |
} | |
class TV { | |
turnOn() { | |
console.log('TV is turning on...'); | |
} | |
turnOff() { | |
console.log('TV is turning off...'); | |
} | |
} | |
class PopcornMaker { | |
turnOn() { | |
console.log('Popcorn maker is turning on...'); | |
} | |
turnOff() { | |
console.log('Popcorn maker is turning off...'); | |
} | |
pop() { | |
console.log('Popping corn!'); | |
} | |
} | |
class HomeTheaterFacade { | |
private amp: Amplifier; | |
private bluray: BlurayPlayer; | |
private lights: Lights; | |
private tv: TV; | |
private popcornMaker: PopcornMaker; | |
constructor({ | |
amp, | |
bluray, | |
lights, | |
tv, | |
popcornMaker, | |
}: { | |
amp: Amplifier; | |
bluray: BlurayPlayer; | |
lights: Lights; | |
tv: TV; | |
popcornMaker: PopcornMaker; | |
}) { | |
this.amp = amp; | |
this.bluray = bluray; | |
this.lights = lights; | |
this.tv = tv; | |
this.popcornMaker = popcornMaker; | |
} | |
watchMovie() { | |
this.popcornMaker.turnOn(); | |
this.popcornMaker.pop(); | |
this.lights.dim(); | |
this.tv.turnOn(); | |
this.amp.on(); | |
this.amp.setSource('bluray'); | |
this.amp.setVolume(11); | |
this.bluray.on(); | |
this.bluray.play(); | |
} | |
endMovie() { | |
this.popcornMaker.turnOff(); | |
this.amp.turnOff(); | |
this.tv.turnOff(); | |
this.bluray.turnOff(); | |
} | |
} | |
// ======================================================== | |
const homeTheater = new HomeTheaterFacade({ | |
amp: new Amplifier(), | |
bluray: new BlurayPlayer(), | |
lights: new Lights(), | |
tv: new TV(), | |
popcornMaker: new PopcornMaker(), | |
}); | |
homeTheater.watchMovie(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface IResource { | |
fetch(): void; | |
} | |
class ResourceProxy implements IResource { | |
constructor(private resource: Resource) {} | |
fetch() { | |
console.log('invoke resource fetch method'); | |
this.resource.fetch(); | |
} | |
} | |
class Resource implements IResource { | |
fetch() { | |
console.log('fetching resource'); | |
} | |
} | |
const proxy = new ResourceProxy(new Resource()); | |
proxy.fetch(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment