design_patterns_in_typescript 学习
https://github.com/torokmark/design_patterns_in_typescript
Creational
Singleton [A class of which only a single instance can exist.]
class GameMain{ constructor() { let singleton1 = SingletonPattern.Singleton.getInstance(); let singleton2 = SingletonPattern.Singleton.getInstance(); if(singleton1 === singleton2) { console.log("two singletons are equivalent"); } else { console.log("two singletons are not equivalent"); } } } namespace SingletonPattern { export class Singleton { // A variable which stores the singleton object.Initially, // the variable acts like a placeholder private static singleton: Singleton; // private constructor so that no instance is created private constructor() { } // This is how we create a singleton object public static getInstance(): Singleton { // check if an instance of the class is already created if(!Singleton.singleton) { // if not created,create an instance of the class // store the instance in the variable Singleton.singleton = new Singleton(); } // return the singleton object return Singleton.singleton; } } } new GameMain();
Abstract Factory [Creates an instance of several families of classes.]
class GameMain{ constructor() { let factory1:AbstractFactoryPattern.IAbstractFactory = new AbstractFactoryPattern.ConcreteFactory1(); let test1:AbstractFactoryPattern.Tester = new AbstractFactoryPattern.Tester(factory1); test1.test(); let factory2:AbstractFactoryPattern.IAbstractFactory = new AbstractFactoryPattern.ConcreteFactory2(); let test2:AbstractFactoryPattern.Tester = new AbstractFactoryPattern.Tester(factory2); test2.test(); } } namespace AbstractFactoryPattern { export interface IAbstractProductA { methodA():string; } export interface IAbstractProductB { methodB():number; } export interface IAbstractFactory { createProductA(param?:any):IAbstractProductA; createProductB():IAbstractProductB; } export class ProductA1 implements IAbstractProductA { methodA = () => { return "This is methodA of ProductA1"; } } export class ProductB1 implements IAbstractProductB { methodB = () => { return 1; } } export class ProductA2 implements IAbstractProductA { methodA = () => { return "This is methodA of ProductA2"; } } export class ProductB2 implements IAbstractProductB { methodB = () => { return 2; } } export class ConcreteFactory1 implements IAbstractFactory { createProductA(param?:any):IAbstractProductA { return new ProductA1(); } createProductB():IAbstractProductB { return new ProductB1(); } } export class ConcreteFactory2 implements IAbstractFactory { createProductA(param?:any):IAbstractProductA { return new ProductA2(); } createProductB():IAbstractProductB { return new ProductB2(); } } export class Tester { private abstractProductA:IAbstractProductA; private abstractProductB:IAbstractProductB; constructor(factory:IAbstractFactory) { this.abstractProductA = factory.createProductA(); this.abstractProductB = factory.createProductB(); } public test():void { console.log(this.abstractProductA.methodA()); console.log(this.abstractProductB.methodB()); } } } new GameMain();
Factory Method [Facilitates the creation of other objects.]
class GameMain{ constructor() { let a:FactoryMethodPattern.IAbstractProduct = FactoryMethodPattern.ProductFactory.createProduct("A"); let b:FactoryMethodPattern.IAbstractProduct = FactoryMethodPattern.ProductFactory.createProduct("B"); console.log(a.method()); console.log(b.method()); } } namespace FactoryMethodPattern { export interface IAbstractProduct { method(param?:any):void; } export class ConcreteProductA implements IAbstractProduct { method = (param?:any) => { return "Method of ConcreteProductA"; } } export class ConcreteProductB implements IAbstractProduct { method = (param?:any) => { return "Method of ConcreteProductB"; } } export namespace ProductFactory { export function createProduct(type:string):IAbstractProduct { if(type === "A") { return new ConcreteProductA(); } else if(type === "B") { return new ConcreteProductB(); } return null; } } } new GameMain();
Builder [Solves the problem of telescoping constructor.]
class GameMain{ constructor() { let u:BuilderPattern.User = new BuilderPattern.UserBuilder("Jancsi") .setAge(12) .setPhone("0123456789") .setAddress("asdf") .build(); console.log(u.Name + " " + u.Age + " " + u.Phone + " " + u.Address); } } namespace BuilderPattern { export class UserBuilder { private name:string; private age:number; private phone:string; private address:string; constructor(name:string) { this.name = name; } get Name() { return this.name; } setAge(value:number):UserBuilder { this.age = value; return this; } get Age() { return this.age; } setPhone(value:string):UserBuilder { this.phone = value; return this; } get Phone() { return this.phone; } setAddress(value:string):UserBuilder { this.address = value; return this; } get Address() { return this.address; } build():User { return new User(this); } } export class User { private name:string; private age:number; private phone:string; private address:string; constructor(builder:UserBuilder) { this.name = builder.Name; this.age = builder.Age; this.phone = builder.Phone; this.address = builder.Address; } get Name() { return this.name; } get Age() { return this.age; } get Phone() { return this.phone; } get Address() { return this.address; } } } new GameMain();
Prototype
class GameMain{ constructor() { let builder:PrototypePattern.Builder = new PrototypePattern.Builder(); for(let i = 1; i <= 3; i += 1) { console.log(builder.createOne("c" + i).toString()); } } } namespace PrototypePattern { export interface IPrototype { clone():IPrototype; toString():string; } export class Concrete1 implements IPrototype { clone():IPrototype { return new Concrete1(); } toString():string { return "This is Concrete1"; } } export class Concrete2 implements IPrototype { clone():IPrototype { return new Concrete2(); } toString():string { return "This is Concrete2"; } } export class Concrete3 implements IPrototype { clone():IPrototype { return new Concrete3(); } toString():string { return "This is Concrete3"; } } export class Builder { private prototypeMap: { [s:string]:IPrototype;} = {}; constructor() { this.prototypeMap['c1'] = new Concrete1(); this.prototypeMap['c2'] = new Concrete2(); this.prototypeMap['c3'] = new Concrete3(); } createOne(s:string):IPrototype { console.log(s); return this.prototypeMap[s].clone(); } } } new GameMain();
Structural Patterns
Adapter [Convert the interface of class into another interface clients expect. Adapter lets class work together that couldn't otherwise because of incompatible interfaces.]
class GameMain{ constructor() { let adapter:AdapterPattern.Adapter = new AdapterPattern.Adapter(); adapter.call(); } } namespace AdapterPattern { export class Adaptee { public method():void { console.log("'method' of Adaptee is being called"); } } export interface ITarget { call():void } export class Adapter implements ITarget { public call():void { console.log("Adapter's 'call' method is being called"); let adaptee:Adaptee = new Adaptee(); adaptee.method(); } } } new GameMain();
Bridge [decouple an abstraction from its implementation so that the two can vary independently.]
class GameMain{ constructor() { let abstractionA:BridgePattern.Abstraction = new BridgePattern.RefinedAbstractionA(new BridgePattern.ConcreteImplementorA()); let abstractionB:BridgePattern.Abstraction = new BridgePattern.RefinedAbstractionB(new BridgePattern.ConcreteImplementorB()); abstractionA.callIt("abstractionA"); abstractionB.callIt("abstractionB"); } } namespace BridgePattern { export class Abstraction { implementor:IImplementor; constructor(imp:IImplementor) { this.implementor = imp; } public callIt(s:string):void { throw new Error("This method is abstract!"); } } export class RefinedAbstractionA extends Abstraction { constructor(imp:IImplementor) { super(imp) } public callIt(s:string):void { console.log("This is RefinedAbstractionA"); this.implementor.callee(s); } } export class RefinedAbstractionB extends Abstraction { constructor(imp:IImplementor) { super(imp); } public callIt(s:string):void { console.log("This is RefinedAbstractionB"); this.implementor.callee(s); } } export interface IImplementor { callee(s:any):void; } export class ConcreteImplementorA implements IImplementor { public callee(s:any):void { console.log("'callee' of ConcreteImplementorA is being called."); console.log(s); } } export class ConcreteImplementorB implements IImplementor { public callee(s:any):void { console.log("'callee' of ConcreteImplementorB is being called."); console.log(s); } } } new GameMain();
Composite [lets clients treat individual objects and compositions uniformly.]
class GameMain{ constructor() { let leaf1 = new CompositePattern.Leaf("1"); let leaf2 = new CompositePattern.Leaf("2"); let leaf3 = new CompositePattern.Leaf("3"); let composite1 = new CompositePattern.Composite("Comp1"); let composite2 = new CompositePattern.Composite("Comp2"); composite1.add(leaf1); composite1.add(leaf2); composite1.add(leaf3); composite1.remove(2); composite2.add(leaf1); composite2.add(leaf3); composite1.operation(); composite2.operation(); } } namespace CompositePattern { export interface IComponent { operation():void; } export class Composite implements IComponent { private list:Array<IComponent>; private s:string; constructor(s:string) { this.list = new Array<IComponent>(); this.s = s; } public operation():void { console.log("'operation' of ",this.s); for(let i = 0; i < this.list.length; i++) { this.list[i].operation(); } } public add(c:IComponent):void { this.list.push(c); } public remove(i:number):void { if(this.list.length <= i) { throw new Error("index out of boud!"); } this.list.splice(i,1); } } export class Leaf implements IComponent { private s:string; constructor(s:string) { this.s = s; } public operation():void { console.log("'operation' of Leaf",this.s," is called."); } } } new GameMain();
Decorator [Allows behavior to be added to an individual object dynamically.]
class GameMain{ constructor() { let decorator1:DecoratorPattern.Decorator = new DecoratorPattern.ConcreteDecorator(1,new DecoratorPattern.ConcreteComponent("Component1")); decorator1.operation(); } } namespace DecoratorPattern { export interface IComponent { operation():void; } export class ConcreteComponent implements IComponent { private s:string; constructor(s:string) { this.s = s; } public operation():void { console.log("'operation' of ConcreteComponent",this.s," is being called!"); } } export class Decorator implements IComponent { private component:IComponent; private id:number; constructor(id:number,component:IComponent) { this.id = id; this.component = component; } public get Id():number { return this.id; } public operation():void { this.component.operation(); console.log("'operation' of Decorator",this.id," is being called!"); } } export class ConcreteDecorator extends Decorator { constructor(id:number,component:IComponent) { super(id,component); } public operation():void { super.operation(); console.log("'operation' of ConcreteDecorator",this.Id," is being called!"); } } } new GameMain();
Facade [Substitute the interfaces of a set of classes by the interface of one class. Facade hides implementation classes behind one interface.]
class GameMain{ constructor() { let facade:FacadePattern.Facade = new FacadePattern.Facade(); facade.operation1(); facade.operation2(); } } namespace FacadePattern { export class Part1 { public method1():void { console.log("'method1' of Part1"); } } export class Part2 { public method2():void { console.log("'method2' of Part2"); } } export class Part3 { public method3():void { console.log("'method3' of Part3" ); } } export class Facade { private part1:Part1 = new Part1(); private part2:Part2 = new Part2(); private part3:Part3 = new Part3(); public operation1():void { console.log("'operation1' is called ==="); this.part1.method1(); this.part2.method2(); console.log("======================="); } public operation2():void { console.log("'operation2' is called ==="); this.part1.method1(); this.part3.method3(); console.log("==========================="); } } } new GameMain();
Flyweight [Facilitates the reuse of many fine grained objects, making the utilization of large numbers of objects more efficient.]
class GameMain{ constructor() { let factory:FlyweightPattern.FlyweightFactory = new FlyweightPattern.FlyweightFactory(); let concrete1:FlyweightPattern.ConcreteFlyweight = <FlyweightPattern.ConcreteFlyweight>factory.getFlyweight("concrete1"); let concrete2:FlyweightPattern.ConcreteFlyweight = <FlyweightPattern.ConcreteFlyweight>factory.getFlyweight("concrete2"); concrete1.operation("1"); concrete2.operation("2"); } } namespace FlyweightPattern { export interface IFlyweight { operation(s:string):void; } export class ConcreteFlyweight implements IFlyweight { private intrinsicState:string; constructor(intrinsicState:string) { this.intrinsicState = intrinsicState; } public operation(s:string):void { console.log("'operation' of ConcreteFlyweight",s," is being called!"); } } export class UnsharedConcreteFlyweight implements IFlyweight { private allState:number; constructor(allState:number) { this.allState = allState; } public operation(s:string):void { console.log("'operation' of UnsharedConcreteFlyweight",s," is being called!"); } } export class FlyweightFactory { private filesMap:{[s:string]:IFlyweight;} = <any>{}; constructor() { } public getFlyweight(key:string):IFlyweight { if(this.filesMap[key] == undefined || null) { this.filesMap[key] = new ConcreteFlyweight(key); } return this.filesMap[key]; } } } new GameMain();
Proxy [Provide a surrogate or placeholder for another object to control access to it.]
class GameMain{ constructor() { let proxy1:ProxyPattern.Proxy = new ProxyPattern.Proxy("proxy1"); let proxy2:ProxyPattern.Proxy = new ProxyPattern.Proxy("proxy2"); proxy1.doAction(); proxy1.doAction(); proxy2.doAction(); proxy2.doAction(); proxy1.doAction(); } } namespace ProxyPattern { export interface ISubject { doAction():void; } export class RealSubject implements ISubject { private s:string; constructor(s:string) { this.s = s; } public doAction():void { console.log("'doAction' of RealSubject",this.s," is being called!"); } } export class Proxy implements ISubject { private realSubject:RealSubject; private s:string; constructor(s:string) { this.s = s; } public doAction():void { console.log("'doAction' of Proxy(",this.s,")"); if(this.realSubject === null || this.realSubject === undefined) { console.log("creating a new RealSubject."); this.realSubject = new RealSubject(this.s); } this.realSubject.doAction(); } } } new GameMain();
Behavioral Patterns
Chain of Responsibility [Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.]
class GameMain{ constructor() { let h1:ChainOfResponsibilityPattern.Handler = new ChainOfResponsibilityPattern.ConcreteHandler1(3); let h2:ChainOfResponsibilityPattern.Handler = new ChainOfResponsibilityPattern.ConcreteHandler2(7); let h3:ChainOfResponsibilityPattern.Handler = new ChainOfResponsibilityPattern.ConcreteHandler3(20); let reqs:Array<number> = [2,7,23,34,4,5,8,3]; h1.setHandler(h2); h2.setHandler(h3); for(let i = 0,max = reqs.length; i < max; i++) { h1.operation("operation is fired!",reqs[i]); } } } namespace ChainOfResponsibilityPattern { export class Handler { private handler:Handler; private req:number; constructor(req:number){ this.req = req; } public setHandler(handler:Handler):void { this.handler = handler; } public operation(msg:string,req:number):void { if(req <= this.req) { this.handlerRequest(msg); } else if(this.handler !== null && this.handler !== undefined) { this.handler.operation(msg,req); } } public handlerRequest(msg:string):void { throw new Error("Abstract method!"); } } export class ConcreteHandler1 extends Handler { constructor(req:number) { super(req); } public handlerRequest(msg:string) { console.log("Message (ConcreteHandler1) :: ",msg); } } export class ConcreteHandler2 extends Handler { constructor(req:number) { super(req); } public handlerRequest(msg:string) { console.log("Message (ConcreteHandler2) :: ",msg); } } export class ConcreteHandler3 extends Handler { constructor(req:number) { super(req); } public handlerRequest(msg:string) { console.log("Message (ConcreteHandler3) :: ",msg); } } } new GameMain();
Command [Creates objects which encapsulate actions and parameters.]
class GameMain{ constructor() { let receiver:CommandPattern.Receiver = new CommandPattern.Receiver(); let command1:CommandPattern.Command = new CommandPattern.ConcreteCommand1(receiver); let command2:CommandPattern.Command = new CommandPattern.ConcreteCommand2(receiver); let invoker:CommandPattern.Invoker = new CommandPattern.Invoker(); invoker.storeAndExecute(command1); invoker.storeAndExecute(command2); } } namespace CommandPattern { export class Command { public execute():void { throw new Error("Abstract method!"); } } export class ConcreteCommand1 extends Command { private receiver:Receiver; constructor(receiver:Receiver) { super(); this.receiver = receiver; } public execute():void { console.log("'execute' method of ConcreteCommand1 is being called!"); this.receiver.action(); } } export class ConcreteCommand2 extends Command { private receiver:Receiver; constructor(receiver:Receiver) { super(); this.receiver = receiver; } public execute():void { console.log("'execute' method of ConcreteCommand2 is being called!"); this.receiver.action(); } } export class Invoker { private commands:Command[]; constructor() { this.commands = []; } public storeAndExecute(cmd:Command) { this.commands.push(cmd); cmd.execute(); } } export class Receiver { public action():void { console.log("action is being called!"); } } } new GameMain();
Interpreter [Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.]
class GameMain{ constructor() { let context:InterpreterPattern.Context = new InterpreterPattern.Context(); let list = []; list.push(new InterpreterPattern.NonterminalExpression()); list.push(new InterpreterPattern.NonterminalExpression()); list.push(new InterpreterPattern.NonterminalExpression()); list.push(new InterpreterPattern.TerminalExpresss()); list.push(new InterpreterPattern.NonterminalExpression()); list.push(new InterpreterPattern.NonterminalExpression()); list.push(new InterpreterPattern.TerminalExpresss()); list.push(new InterpreterPattern.TerminalExpresss()); for(let i = 0,max = list.length;i < max;i++) { list[i].interpret(context); } } } namespace InterpreterPattern { export class Context { } export interface IAbstractExpression { interpret(context:Context):void; } export class TerminalExpresss implements IAbstractExpression { public interpret(context:Context):void { console.log("'interpret' method of TerminalExpression is being called!"); } } export class NonterminalExpression implements IAbstractExpression { public interpret(context:Context):void { console.log("'interpret' method of NonterminalExpression is being called!"); } } } new GameMain();
Iterator [Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.]
class GameMain{ constructor() { let nArray = [1,7,21,657,3,2,765,13,65]; let numbers:IteratorPattern.Numbers = new IteratorPattern.Numbers(nArray); let it:IteratorPattern.ConcreteIterator = <IteratorPattern.ConcreteIterator>numbers.createIIterator(); while(it.hasNext()){ console.log(it.next()); } } } namespace IteratorPattern { export interface IIterator { next():any; hasNext():boolean; } export interface IAggregator { createIIterator():IIterator; } export class ConcreteIterator implements IIterator { private collection:any[] = []; private position:number = 0; constructor(collection:any[]) { this.collection = collection; } public next():any { let result = this.collection[this.position]; this.position ++; return result; } public hasNext():boolean { return this.position < this.collection.length; } } export class Numbers implements IAggregator { private collection:number[] = []; constructor(collection:number[]) { this.collection = collection; } public createIIterator():IIterator { return new ConcreteIterator(this.collection); } } } new GameMain();
Mediator [Promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.]
class GameMain{ constructor() { let cm:MediatorPattern.ConcreteMediator = new MediatorPattern.ConcreteMediator(); let c1:MediatorPattern.ConcreteColleagueA = new MediatorPattern.ConcreteColleagueA(cm); let c2:MediatorPattern.ConcreteColleagueB = new MediatorPattern.ConcreteColleagueB(cm); cm.conreteColleagueA = c1; cm.conreteColleagueB = c2; c1.send("'send' of ConcreteColleaugeA is being called!"); c2.send("'send' of ConcreteColleagueB is being called!"); } } namespace MediatorPattern { export interface IMediator { send(msg:string,colleague:Colleague):void; } export class Colleague { public mediator:IMediator; constructor(mediator:IMediator) { this.mediator = mediator; } public send(msg:string):void { throw new Error("Abstract Method!"); } public receive(msg:string):void { throw new Error("Abstract Method!"); } } export class ConcreteColleagueA extends Colleague { constructor(mediator:IMediator) { super(mediator) } public send(msg:string):void { this.mediator.send(msg,this); } public receive(msg:string):void { console.log(msg,"'receive' of ConcreteColleagueA is being called!"); } } export class ConcreteColleagueB extends Colleague { constructor(mediator:IMediator) { super(mediator) } public send(msg:string):void { this.mediator.send(msg,this) } public receive(msg:string):void { console.log(msg,"'receive' of ConcreteColleagueB is being called!"); } } export class ConcreteMediator implements IMediator { public conreteColleagueA:ConcreteColleagueA; public conreteColleagueB:ConcreteColleagueB; public send(msg:string,colleague:Colleague):void { if(this.conreteColleagueA === colleague) { this.conreteColleagueA.receive(msg); } else { this.conreteColleagueB.receive(msg); } } } } new GameMain();
Memento [Capture an object’s internal state and externalize it so that it can be restored to that state later.]
class GameMain{ constructor() { let state:MementoPattern.State = new MementoPattern.State("...State "); let originator:MementoPattern.Originator = new MementoPattern.Originator(state); let careTaker:MementoPattern.CareTaker = new MementoPattern.CareTaker(); careTaker.Memento = originator.createMemento(); originator.State = new MementoPattern.State("something else..."); originator.setMemento(careTaker.Memento); } } namespace MementoPattern { export class State { private str:string; constructor(str:string) { this.str = str; } get Str():string { return this.str; } set Str(str:string) { this.str = str; } } export class Originator { private state:State; constructor(state:State) { this.state = state; } get State():State { return this.state; } set State(state:State) { console.log("State :: ",state); this.state = state; } public createMemento():Memento { console.log("creates a memento with a given state!"); return new Memento(this.state) } public setMemento(memento:Memento) { console.log("sets the state back"); this.State = memento.State; } } export class Memento { private state:State; constructor(state:State) { this.state = state; } get State():State { console.log("get memento's state"); return this.state; } } export class CareTaker { private memento:Memento; get Memento():Memento { return this.memento; } set Memento(memento:Memento) { this.memento = memento; } } } new GameMain();
Observer [Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.]
class GameMain{ constructor() { let sub:ObserverPattern.ConcreteSubject = new ObserverPattern.ConcreteSubject(); sub.register(new ObserverPattern.ConcreteObserver(sub,"Jancsi")); sub.register(new ObserverPattern.ConcreteObserver(sub,"Julcsa")); sub.register(new ObserverPattern.ConcreteObserver(sub,"Marcsa")); sub.SubjectState = 123; sub.notify(); } } namespace ObserverPattern { export class Subject { private observers:Observer[] = []; public register(observer:Observer):void { console.log(observer,"is pushed!"); this.observers.push(observer); } public unregister(observer:Observer):void { let n:number = this.observers.indexOf(observer); console.log(observer,"is removed"); this.observers.splice(n,1); } public notify():void { console.log("notify all the observers",this.observers); for(let i = 0,max = this.observers.length;i < max;i++) { this.observers[i].notify(); } } } export class ConcreteSubject extends Subject { private subjectState:number; get SubjectState():number { return this.subjectState; } set SubjectState(subjectState:number) { this.subjectState = subjectState; } } export class Observer { public notify():void { throw new Error("Abstract Method!"); } } export class ConcreteObserver extends Observer { private name:string; private state:number; private subject:ConcreteSubject; constructor(subject:ConcreteSubject,name:string) { super(); console.log("ConcreteObserver",name,"is created!"); this.subject = subject; this.name = name; } public notify():void { console.log("ConcreteObserver's notify method"); this.state = this.subject.SubjectState; console.log(this.name,this.state); } get Subject():ConcreteSubject { return this.subject; } set Subject(subject:ConcreteSubject){ this.subject = subject; } } } new GameMain();
State [A cleaner way for an object to change its behavior at runtime without resorting to large monolithic conditional statements.]
class GameMain{ constructor() { let context:StatePattern.Context = new StatePattern.Context(new StatePattern.ConcreteStateA()); context.request(); context.request(); context.request(); context.request(); context.request(); context.request(); context.request(); context.request(); } } namespace StatePattern { export interface IState { handle(context:Context):void; } export class ConcreteStateA implements IState { public handle(context:Context):void { console.log("'handle' method of ConcreteStateA is being called!"); context.State = new ConcreteStateB(); } } export class ConcreteStateB implements IState { public handle(context:Context):void { console.log("'handle' method of ConcreteStateB is being called!"); context.State = new ConcreteStateA(); } } export class Context { private state:IState; constructor(state:IState) { this.state = state; } get State():IState { return this.state; } set State(state:IState) { this.state = state; } public request():void { console.log("request is being called!"); this.state.handle(this); } } } new GameMain();
Strategy [Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.]
class GameMain{ constructor() { let context:StrategyPattern.Context = new StrategyPattern.Context(new StrategyPattern.ConcreteStrategy1()); context.executeStrategy(); context = new StrategyPattern.Context(new StrategyPattern.ConcreteStrategy2()); context.executeStrategy(); context = new StrategyPattern.Context(new StrategyPattern.ConcreteStrategy3()); context.executeStrategy(); } } namespace StrategyPattern { export interface IStrategy { execute():void } export class ConcreteStrategy1 implements IStrategy { public execute():void { console.log("'execute' method of ConcreteStrategy1 is being called."); } } export class ConcreteStrategy2 implements IStrategy { public execute():void { console.log("'execute' method of ConcreteStrategy2 is being called."); } } export class ConcreteStrategy3 implements IStrategy { public execute():void { console.log("'execute' method of ConcreteStrategy3 is being called."); } } export class Context { private strategy:IStrategy; constructor(strategy:IStrategy){ this.strategy = strategy; } public executeStrategy():void { this.strategy.execute(); } } } new GameMain();
Template Method [Define the basic steps of an algorithm and allow the implementation of the individual steps to be changed.]
class GameMain{ constructor() { let c1:TemplateMethodPattern.ConcreteClass1 = new TemplateMethodPattern.ConcreteClass1(); let c2:TemplateMethodPattern.ConcreteClass2 = new TemplateMethodPattern.ConcreteClass2(); c1.templateMethod(); c2.templateMethod(); } } namespace TemplateMethodPattern { export class AbstractClass { public method1():void { throw new Error("Abstract Method"); } public method2():void { throw new Error("Abstract Method"); } public method3():void { throw new Error("Abstract Method"); } public templateMethod():void { console.log("templateMethod is being called"); this.method1(); this.method2(); this.method3(); } } export class ConcreteClass1 extends AbstractClass { public method1():void { console.log("method1 of ConcreteClass1"); } public method2():void { console.log("method2 of ConcreteClass1"); } public method3():void { console.log("method3 of ConcreteClass1"); } } export class ConcreteClass2 extends AbstractClass { public method1():void { console.log("method1 of ConcreteClass2"); } public method2():void { console.log("method2 of ConcreteClass2"); } public method3():void { console.log("method3 of ConcreteClass2"); } } } new GameMain();
Visitor [Allows for one or more operation to be applied to a set of objects at runtime, decoupling the operations from the object structure.]
class GameMain{ constructor() { let objs:VisitorPattern.Objs = new VisitorPattern.Objs(); objs.attach(new VisitorPattern.ConcreteElement1()); objs.attach(new VisitorPattern.ConcreteElement2()); let v1:VisitorPattern.ConcreteVisitor1 = new VisitorPattern.ConcreteVisitor1(); let v2:VisitorPattern.ConcreteVisitor2 = new VisitorPattern.ConcreteVisitor2(); objs.operate(v1); objs.operate(v2); } } namespace VisitorPattern { export interface IVisitor { visitConcreteElement1(concreteElement1:ConcreteElement1):void; visitConcreteElement2(concreteElement2:ConcreteElement2):void; } export class ConcreteVisitor1 implements IVisitor { public visitConcreteElement1(concreteElement1:ConcreteElement1):void { console.log("'visitConcreteElement1' of ConcreteVisitor1 is being called!"); } public visitConcreteElement2(concreteElement2:ConcreteElement2):void { console.log("'visitConcreteElement2' of ConcreteVisitro1 is being called!"); } } export class ConcreteVisitor2 implements IVisitor { public visitConcreteElement1(concreteElement1:ConcreteElement1):void { console.log("'visitConcreteElement1' of ConcreteVisitor2 is being called!"); } public visitConcreteElement2(concreteElement2:ConcreteElement2):void { console.log("'visitConcreteElement2' of ConcreteVisitor2 is being called!"); } } export interface IElement { operate(visitor:IVisitor):void; } export class ConcreteElement1 implements IElement { public operate(visitor:IVisitor):void { console.log("'operate' of ConcreteElement1 is being called!"); visitor.visitConcreteElement1(this); } } export class ConcreteElement2 implements IElement { public operate(visitor:IVisitor):void { console.log("'operate' of ConcreteElement2 is being called!"); visitor.visitConcreteElement2(this); } } export class Objs { private elements:IElement[] = []; public attach(e:IElement):void { this.elements.push(e); } public detach(e:IElement):void { let index = this.elements.indexOf(e); this.elements.splice(index,1); } public operate(visitor:IVisitor):void { for(let i = 0,max = this.elements.length;i < max;i++) { this.elements[i].operate(visitor); } } } } new GameMain();