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();
View Code

  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();
View Code

  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();
View Code

  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();
View Code

  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();
View Code

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();
View Code

  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();
View Code

  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();
View Code

  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();
View Code

  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();
View Code

  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();
View Code

  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();
View Code

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();
View Code

  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();
View Code

  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();
View Code

  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();
View Code

  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();
View Code

  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();
View Code

  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();
View Code

  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();
View Code

  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();
View Code

  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();
View Code

  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();
View Code

posted on 2018-07-20 15:42  void87  阅读(138)  评论(0编辑  收藏  举报

导航