Last active
June 27, 2020 04:19
-
-
Save luckyyang/cf1cf0ca2d896f7ffec699ef6217a313 to your computer and use it in GitHub Desktop.
Design Pattern: Observer. You can play with it at https://www.typescriptlang.org/play/index.html
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
abstract class Dough { | |
} | |
class ThinDough extends Dough { | |
} | |
class ThickDough extends Dough { | |
} | |
abstract class Sauce { | |
} | |
class MarinaraSauce extends Sauce { | |
} | |
class BruschettaSauce extends Sauce { | |
} | |
abstract class Cheese { | |
} | |
class FrenchCheese extends Cheese { | |
} | |
class ChinaCheese extends Cheese { | |
} | |
interface IngredientFactory { | |
createDough(): Dough | |
createSauce(): Sauce | |
createCheese(): Cheese | |
} | |
class NKIngredientFactory implements IngredientFactory { | |
createDough() { | |
console.log('createDough at NKIngredientFactory: ThinDough') | |
return new ThinDough() | |
} | |
createSauce() { | |
console.log('createSauce at NKIngredientFactory: MarinaraSauce') | |
return new MarinaraSauce() | |
} | |
createCheese() { | |
console.log('createCheese at NKIngredientFactory: FrenchCheese') | |
return new FrenchCheese() | |
} | |
} | |
class ChicagoIngredientFactory implements IngredientFactory { | |
createDough() { | |
console.log('createDough at ChicagoIngredientFactory: ThickDough') | |
return new ThickDough() | |
} | |
createSauce() { | |
console.log('createSauce at ChicagoIngredientFactory: BruschettaSauce') | |
return new BruschettaSauce() | |
} | |
createCheese() { | |
console.log('createCheese at ChicagoIngredientFactory: ChinaCheese') | |
return new ChinaCheese() | |
} | |
} | |
abstract class Pizza { | |
name!: string | |
dough!: Dough | |
sauce!: Sauce | |
cheese!: Cheese | |
abstract prepare(): void | |
bake() { | |
console.log('bake') | |
} | |
slice() { | |
console.log('slice') | |
} | |
box() { | |
console.log('box') | |
} | |
} | |
class NKStyleCheesePizza extends Pizza { | |
ingredientFactory!: IngredientFactory | |
constructor(ingredientFactory: IngredientFactory) { | |
super() | |
this.name = 'NKStyleCheesePizza' | |
this.ingredientFactory = ingredientFactory | |
} | |
prepare() { | |
console.log('prepare start') | |
this.dough = this.ingredientFactory.createSauce() | |
console.log('prepare end') | |
} | |
} | |
class ChicagoStyleCheesePizza extends Pizza { | |
ingredientFactory!: IngredientFactory | |
constructor(ingredientFactory: IngredientFactory) { | |
super() | |
this.name = 'ChicagoStyleCheesePizza' | |
this.ingredientFactory = ingredientFactory | |
} | |
prepare() { | |
console.log('prepare start') | |
this.sauce = this.ingredientFactory.createSauce() | |
console.log('prepare end') | |
} | |
} | |
class NKStyleViggiePizza extends Pizza { | |
ingredientFactory!: IngredientFactory | |
constructor(ingredientFactory: IngredientFactory) { | |
super() | |
this.name = 'ChicagoStyleCheesePizza' | |
this.ingredientFactory = ingredientFactory | |
} | |
prepare() { | |
console.log('prepare start') | |
this.sauce = this.ingredientFactory.createSauce() | |
this.dough = this.ingredientFactory.createSauce() | |
this.cheese = this.ingredientFactory.createCheese() | |
console.log('prepare end') | |
} | |
} | |
class ChicagoStyleViggiePizza extends Pizza { | |
ingredientFactory!: IngredientFactory | |
constructor(ingredientFactory: IngredientFactory) { | |
super() | |
this.name = 'ChicagoStyleCheesePizza' | |
this.ingredientFactory = ingredientFactory | |
} | |
prepare() { | |
console.log('prepare start') | |
this.dough = this.ingredientFactory.createSauce() | |
this.sauce = this.ingredientFactory.createSauce() | |
this.cheese = this.ingredientFactory.createCheese() | |
console.log('prepare end') | |
} | |
} | |
abstract class PizzaStore { | |
orderPizza(type: string): Pizza { | |
let pizza: Pizza | |
pizza = this.createPizze(type) | |
pizza.prepare() | |
pizza.bake() | |
pizza.slice() | |
pizza.box() | |
return pizza | |
} | |
abstract createPizze(type: string): Pizza; | |
} | |
class NewYorkPizzaStore extends PizzaStore { | |
ingredientFactory: IngredientFactory = new NKIngredientFactory() | |
createPizze(type: string): Pizza { | |
let pizza: Pizza | |
if (type === 'cheese') { | |
pizza = new NKStyleCheesePizza(this.ingredientFactory) | |
} else { | |
pizza = new NKStyleViggiePizza(this.ingredientFactory) | |
} | |
return pizza; | |
} | |
} | |
class ChicagoPizzaStore extends PizzaStore { | |
ingredientFactory: IngredientFactory = new NKIngredientFactory() | |
createPizze(type: string): Pizza { | |
let pizza: Pizza | |
if (type === 'cheese') { | |
pizza = new ChicagoStyleCheesePizza(this.ingredientFactory) | |
} else { | |
pizza = new ChicagoStyleViggiePizza(this.ingredientFactory) | |
} | |
return pizza; | |
} | |
} | |
function main() { | |
console.log('orderPizza from NKStore') | |
const NKStore: PizzaStore = new NewYorkPizzaStore(); | |
NKStore.orderPizza('cheese') | |
console.log('orderPizza from ChicagoStore') | |
const ChicagoStore: PizzaStore = new NewYorkPizzaStore(); | |
ChicagoStore.orderPizza('viggie') | |
} | |
main(); | |
Will output: | |
orderPizza from NKStore | |
prepare start | |
createSauce at NKIngredientFactory: MarinaraSauce | |
prepare end | |
bake | |
slice | |
box | |
orderPizza from ChicagoStore | |
prepare start | |
createSauce at NKIngredientFactory: MarinaraSauce | |
createSauce at NKIngredientFactory: MarinaraSauce | |
createCheese at NKIngredientFactory: FrenchCheese | |
prepare end | |
bake | |
slice | |
box |
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 SignProvider { | |
sign(): void; | |
} | |
class KeyperAdapter implements SignProvider { | |
keyper!: Keyper | |
constructor(keyper: Keyper) { | |
this.keyper = keyper | |
} | |
sign() { | |
this.keyper.signWithLock() | |
} | |
} | |
class HardwareSignerAdapter implements SignProvider { | |
hardwareSigner!: HardwareSigner | |
constructor(hardwareSigner: HardwareSigner) { | |
this.hardwareSigner = hardwareSigner | |
} | |
sign() { | |
this.hardwareSigner.signWithUSB() | |
} | |
} | |
class HardwareSigner { | |
signWithUSB() { | |
console.log('HardwareSigner: signWithUSB') | |
} | |
} | |
class Keyper { | |
signWithLock() { | |
console.log('Keyper: signWithLock') | |
} | |
} | |
function main() { | |
const keyper = new Keyper() | |
const signProvider = new KeyperAdapter(keyper) | |
signProvider.sign() | |
const hardwareSigner = new HardwareSigner() | |
const hardwareSignProvider = new HardwareSignerAdapter(hardwareSigner) | |
hardwareSignProvider.sign() | |
} | |
main() | |
Will output: | |
Keyper: signWithLock | |
HardwareSigner: signWithUSB |
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 Command { | |
execute(): void | |
} | |
class NoCommand implements Command { | |
execute() { | |
console.log('No Command~') | |
} | |
} | |
class TxSignCommand implements Command { | |
ckb!: any | |
constructor(ckb: any) { | |
this.ckb = ckb | |
} | |
execute() { | |
this.ckb.sign() | |
} | |
} | |
class TxSendCommand implements Command { | |
ckb!: CKB | |
constructor(ckb: CKB) { | |
this.ckb = ckb | |
} | |
execute() { | |
this.ckb.send() | |
} | |
} | |
class GetLocksCommand implements Command { | |
synapse!: Synapse | |
constructor(synapse: Synapse) { | |
this.synapse = synapse | |
} | |
execute() { | |
this.synapse.getLocks() | |
} | |
} | |
class GetAddressInfoCommand implements Command { | |
synapse!: any | |
constructor(synapse: any) { | |
this.synapse = synapse | |
} | |
execute() { | |
this.synapse.getAddressInfo() | |
} | |
} | |
class CKB { | |
sign() { | |
console.log('CKB: sign') | |
} | |
send() { | |
console.log('CKB: send') | |
} | |
} | |
class Synapse { | |
getLocks() { | |
console.log('Synapse: getLocks') | |
} | |
getAddressInfo() { | |
console.log('Synapse: getAddressInfo') | |
} | |
} | |
class DApp { | |
buttonCommands!: Command[] | |
constructor() { | |
const arr = [] | |
for (let i = 0; i <= 3; i++) { | |
arr[i] = new NoCommand() | |
} | |
this.buttonCommands = arr | |
} | |
setCommand(index: number, command: Command): void { | |
this.buttonCommands[index] = command | |
} | |
onCommandCalled(index: number): void { | |
this.buttonCommands[index].execute() | |
} | |
} | |
function main() { | |
const dapp = new DApp() | |
const ckb = new CKB() | |
const synapse = new Synapse() | |
const txSendCommand = new TxSendCommand(ckb) | |
const txSignCommand = new TxSignCommand(ckb) | |
const getLocksCommand = new GetLocksCommand(synapse) | |
const getAddressInfoCommand = new GetAddressInfoCommand(synapse) | |
dapp.setCommand(0, txSendCommand) | |
dapp.setCommand(1, txSignCommand) | |
dapp.setCommand(2, getLocksCommand) | |
dapp.setCommand(3, getAddressInfoCommand) | |
dapp.onCommandCalled(0) | |
dapp.onCommandCalled(1) | |
dapp.onCommandCalled(2) | |
dapp.onCommandCalled(3) | |
} | |
main() | |
Will output: | |
CKB: send | |
CKB: sign | |
Synapse: getLocks | |
Synapse: getAddressInfo |
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 SignProvider { | |
sign(): void; | |
} | |
class KeyperAdapter implements SignProvider { | |
keyper!: Keyper | |
constructor(keyper: Keyper) { | |
this.keyper = keyper | |
} | |
sign() { | |
this.keyper.signWithLock() | |
} | |
} | |
class HardwareSignerAdapter implements SignProvider { | |
hardwareSigner!: HardwareSigner | |
constructor(hardwareSigner: HardwareSigner) { | |
this.hardwareSigner = hardwareSigner | |
} | |
sign() { | |
this.hardwareSigner.signWithUSB() | |
} | |
} | |
class HardwareSigner { | |
signWithUSB() { | |
console.log('HardwareSigner: signWithUSB') | |
} | |
} | |
class Keyper { | |
signWithLock() { | |
console.log('Keyper: signWithLock') | |
} | |
} | |
class SignAllFacade { | |
keyper!: Keyper | |
hardwareSigner!: HardwareSigner | |
constructor(keyper: Keyper, hardwareSigner: HardwareSigner) { | |
this.keyper = keyper | |
this.hardwareSigner = hardwareSigner | |
} | |
sign() { | |
this.keyper.signWithLock() | |
this.hardwareSigner.signWithUSB() | |
} | |
} | |
function main() { | |
const keyper = new Keyper() | |
const hardwareSigner = new HardwareSigner() | |
const signAllProvider: SignAllFacade = new SignAllFacade(keyper, hardwareSigner) | |
signAllProvider.sign() | |
} | |
main() | |
Will output: | |
Keyper: signWithLock | |
HardwareSigner: signWithUSB |
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
abstract class Pizza { | |
name: string = '' | |
dough: string = '' | |
sauce: string = '' | |
prepare() { | |
console.log('prepare') | |
} | |
bake() { | |
console.log('bake') | |
} | |
slice() { | |
console.log('slice') | |
} | |
box() { | |
console.log('box') | |
} | |
} | |
class NKStyleCheesePizza extends Pizza { | |
constructor() { | |
super() | |
this.name = 'NKStyleCheesePizza' | |
this.dough = this.name + ' dough' | |
this.sauce = this.name + ' sauce' | |
} | |
} | |
class ChicagoStyleCheesePizza extends Pizza { | |
constructor() { | |
super() | |
this.name = 'NKStyleCheesePizza' | |
this.dough = this.name + ' dough' | |
this.sauce = this.name + ' sauce' | |
} | |
} | |
class NKStyleViggiePizza extends Pizza { | |
constructor() { | |
super() | |
this.name = 'NKStyleCheesePizza' | |
this.dough = this.name + ' dough' | |
this.sauce = this.name + ' sauce' | |
} | |
} | |
class ChicagoStyleViggiePizza extends Pizza { | |
constructor() { | |
super() | |
this.name = 'NKStyleCheesePizza' | |
this.dough = this.name + ' dough' | |
this.sauce = this.name + ' sauce' | |
} | |
} | |
abstract class PizzaStore { | |
orderPizza(type: string): Pizza { | |
let pizza: Pizza | |
pizza = this.createPizze(type) | |
pizza.prepare() | |
pizza.bake() | |
pizza.slice() | |
pizza.box() | |
return pizza | |
} | |
abstract createPizze(type: string): Pizza; | |
} | |
class NewYorkPizzaStore extends PizzaStore { | |
createPizze(type: string): Pizza { | |
let pizza: Pizza | |
if (type === 'cheese') { | |
pizza = new NKStyleCheesePizza() | |
} else { | |
pizza = new NKStyleViggiePizza() | |
} | |
return pizza; | |
} | |
} | |
class ChicagoPizzaStore extends PizzaStore { | |
createPizze(type: string): Pizza { | |
let pizza: Pizza | |
if (type === 'cheese') { | |
pizza = new ChicagoStyleCheesePizza() | |
} else { | |
pizza = new ChicagoStyleViggiePizza() | |
} | |
return pizza; | |
} | |
} | |
function main() { | |
console.log('orderPizza from NKStore') | |
const NKStore: PizzaStore = new NewYorkPizzaStore(); | |
NKStore.orderPizza('cheese') | |
console.log('orderPizza from ChicagoStore') | |
const ChicagoStore: PizzaStore = new NewYorkPizzaStore(); | |
ChicagoStore.orderPizza('viggie') | |
} | |
main(); | |
Will output: | |
orderPizza from NKStore | |
prepare | |
bake | |
slice | |
box | |
orderPizza from ChicagoStore | |
prepare | |
bake | |
slice | |
box |
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
abstract class NumberGenerator { | |
observers: Observer[] = []; | |
addObserver(observer: Observer) { | |
this.observers.push(observer); | |
} | |
removeObserver() { | |
// TODO | |
} | |
notifyObservers(generator: NumberGenerator) { | |
this.observers.forEach((observer) => observer.update(this)); | |
} | |
abstract getNumber(): number; | |
abstract execute(): void; | |
} | |
class RandomNumberGenerator extends NumberGenerator { | |
number: number = 0; | |
getNumber() { | |
return this.number; | |
} | |
execute() { | |
this.number = 2; | |
this.notifyObservers(this); | |
} | |
} | |
interface Observer { | |
update(generator: NumberGenerator): void; | |
} | |
class DigitObserver implements Observer { | |
update(generator: NumberGenerator) { | |
const num = generator.getNumber(); | |
const updatedNum = num * 2; | |
console.log('DigitObserver get number, will do some updates: ', updatedNum); | |
} | |
} | |
class GraphObserver implements Observer { | |
update(generator: NumberGenerator) { | |
const num = generator.getNumber(); | |
const updatedNum = num * 4; | |
console.log('GraphObserver: get number, will do some updates: ', updatedNum); | |
} | |
} | |
const dObserver = new DigitObserver(); | |
const gObserver = new GraphObserver(); | |
const subjectInstance = new RandomNumberGenerator(); | |
subjectInstance.addObserver(dObserver); | |
subjectInstance.addObserver(gObserver); | |
subjectInstance.execute(); | |
// Will output on console log: | |
// DigitObserver get number, will do some updates: 4 | |
// GraphObserver: get number, will do some updates: 8 |
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 Singleton { | |
private static instance: Singleton | |
private constructor() {} | |
static getInstance(): Singleton { | |
if (!Singleton.instance) { | |
Singleton.instance = new Singleton() | |
} | |
return Singleton.instance | |
} | |
public someBusinessLogic() { | |
// ... | |
} | |
} | |
function main() { | |
const s1 = Singleton.getInstance(); | |
const s2 = Singleton.getInstance(); | |
if (s1 === s2) { | |
console.log('Singleton works! They are the same instance.'); | |
} else { | |
console.log('Singleton failed. They are different instances.'); | |
} | |
} | |
main(); | |
Will output: | |
Singleton works! They are the same instance. |
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 Context { | |
changeState: Function; | |
setClock: Function; | |
callSecurityCenter: Function; | |
recordLog: Function; | |
} | |
interface State { | |
doClock: Function; | |
doUse: Function; | |
doAlarm: Function; | |
doPhone: Function; | |
} | |
class SafeFrame implements Context { | |
private state: State = DayState.getInstance(); | |
setClock(i: number) { | |
this.state.doClock(this, i); | |
} | |
changeState(state: State) { | |
this.state = state; | |
} | |
callSecurityCenter() { | |
this.state.doAlarm() | |
} | |
recordLog() { | |
this.state.doPhone() | |
} | |
} | |
class DayState implements State { | |
private static singleton: DayState = new DayState(); | |
public static getInstance() { | |
return this.singleton; | |
} | |
doClock(context: Context, i: number) { | |
if (i >= 17 || i < 9) { | |
context.changeState(NightState.getInstance()) | |
} | |
} | |
doUse() { | |
console.log('DayState: doUse is called') | |
} | |
doAlarm() { | |
console.log('DayState: doAlarm is called') | |
} | |
doPhone() { | |
console.log('DayState: doPhone is called') | |
} | |
} | |
class NightState implements State { | |
private static singleton: NightState = new NightState(); | |
static getInstance() { | |
return this.singleton; | |
} | |
doClock(context: Context, i: number) { | |
if (i >= 9 && i < 17) { | |
context.changeState(DayState.getInstance()) | |
} | |
} | |
doUse() { | |
console.log('NightState: doUse is called') | |
} | |
doAlarm() { | |
console.log('NightState: doAlarm is called') | |
} | |
doPhone() { | |
console.log('NightState: doPhone is called') | |
} | |
} | |
function main() { | |
for (let i = 1; i <= 24; i++) { | |
const safeFrame = new SafeFrame(); | |
safeFrame.setClock(i); | |
safeFrame.callSecurityCenter(); | |
} | |
}; | |
main(); |
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
abstract class Lock { | |
signSend() { | |
this.prepareDeps() | |
this.prepareTx() | |
this.sign() | |
this.send() | |
} | |
abstract prepareDeps(): void | |
abstract sign(): void | |
prepareTx() { | |
console.log('super: prepareTx') | |
} | |
send() { | |
console.log('super: send') | |
} | |
} | |
class Anypay extends Lock { | |
prepareDeps() { | |
console.log('Anypay: prepareDeps') | |
} | |
sign() { | |
console.log('Anypay: sign') | |
} | |
} | |
class Keccak extends Lock { | |
prepareDeps() { | |
console.log('Keccak: prepareDeps') | |
} | |
sign() { | |
console.log('Keccak: sign') | |
} | |
} | |
function main() { | |
const anypay = new Anypay() | |
const keccak = new Keccak() | |
anypay.signSend() | |
keccak.signSend() | |
} | |
main() | |
Will output: | |
Anypay: prepareDeps | |
super: prepareTx | |
Anypay: sign | |
super: send | |
Keccak: prepareDeps | |
super: prepareTx | |
Keccak: sign | |
super: send |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment