├── .gitignore ├── README.md ├── package.json ├── src ├── Adapter.ts ├── Bridge.ts ├── Builder.pu ├── Builder.ts ├── BusinessDelegate.ts ├── ChainResponsibility.ts ├── Command.ts ├── Composite.ts ├── CompositeEntity.ts ├── DataAccessObject.ts ├── Decorator.ts ├── Facade.ts ├── Factory.pu ├── Factory.ts ├── Filter.ts ├── Flyweight.ts ├── FrontController.ts ├── InterceptingFilter.ts ├── Interpreter.ts ├── Iterator.ts ├── MVC.ts ├── Mediator.ts ├── Memento.ts ├── NullObject.ts ├── Observer.ts ├── Prototype.ts ├── Proxy.ts ├── ServiceLocator.ts ├── Singleton.ts ├── State.ts ├── Strategy.ts ├── Template.ts ├── TransferObject.ts └── Visitor.ts ├── test ├── Builder.test.ts ├── Factory.test.ts └── Singleton.test.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | 3 | /**/*.js 4 | 5 | /.vscode -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TypeScript Design Pattern 2 | 3 | 设计模式之 TypeScript 实现版本 4 | 5 | 大量代码来源于 [java设计模式](http://www.runoob.com/design-pattern/design-pattern-tutorial.html) 6 | 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-design", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "tsc && ava" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "ava": "^0.18.2", 14 | "typescript": "next" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Adapter.ts: -------------------------------------------------------------------------------- 1 | interface MediaPlayer{ 2 | play(type: string, filename: string) 3 | } 4 | 5 | interface AdvanceMediaPlayer{ 6 | playVlc?(filename: string) 7 | playMp4?(filename: string) 8 | } 9 | 10 | class VlcPlayer implements AdvanceMediaPlayer{ 11 | playVlc(filename){ 12 | console.log("playing vlc file....." + filename) 13 | } 14 | } 15 | 16 | class Mp4Player implements AdvanceMediaPlayer{ 17 | playMp4(filename){ 18 | console.log("playing mp4 file....." + filename) 19 | } 20 | } 21 | 22 | 23 | class MediaAdaper implements MediaPlayer{ 24 | player : AdvanceMediaPlayer; 25 | constructor(type) { 26 | // 根据type 生成哪一个播放类 27 | if(type == "vlc"){ 28 | this.player = new VlcPlayer() 29 | }else if(type == "mp4"){ 30 | this.player = new Mp4Player() 31 | }else{ 32 | return null; 33 | } 34 | } 35 | play(type: string, filename: string){ 36 | // 因为特定的播放类有特定的播放方法,所以还需要再根据type调用特定的播放类 37 | if(type == "vlc"){ 38 | this.player.playVlc(filename); 39 | }else if(type == "mp4"){ 40 | this.player.playMp4(filename) 41 | }else{ 42 | return null; 43 | } 44 | } 45 | } 46 | 47 | 48 | class AudioPlayer implements MediaPlayer{ 49 | MediaAdaper: MediaAdaper; 50 | play(type, filename){ 51 | if(type == 'mp3'){ 52 | console.log("播放器内置支持mp3,"+ filename +"已开始播放!"); 53 | }else if(type == 'vlc' || type == 'mp4'){ 54 | this.MediaAdaper = new MediaAdaper(type); 55 | this.MediaAdaper.play(type, filename) 56 | }else{ 57 | console.log('不支持当前格式!'); 58 | } 59 | } 60 | } 61 | 62 | let player = new AudioPlayer(); 63 | 64 | player.play('mp3', 'aa.mp3'); 65 | player.play('vlc', 'bb.vlc'); 66 | player.play('mp4', 'cc.mp4'); -------------------------------------------------------------------------------- /src/Bridge.ts: -------------------------------------------------------------------------------- 1 | // 桥接模式 2 | 3 | interface DrawApi{ 4 | draw(radius: number, x: number, y: number); 5 | } 6 | 7 | 8 | class RedCircle implements DrawApi{ 9 | draw(radius: number, x : number, y : number){ 10 | console.log('red circle'); 11 | } 12 | } 13 | 14 | 15 | class GreenCircle implements DrawApi{ 16 | draw(radius: number, x: number, y: number){ 17 | console.log('green circle'); 18 | } 19 | } 20 | 21 | abstract class Shape{ 22 | protected drawApi : DrawApi; 23 | protected constructor(drawApi : DrawApi){ 24 | this.drawApi = drawApi; 25 | } 26 | abstract draw(); 27 | } 28 | 29 | class Circle extends Shape{ 30 | private _x : number; 31 | private _y : number; 32 | private _radius: number; 33 | 34 | constructor(x: number, y: number, radius: number, drawApi: DrawApi){ 35 | super(drawApi); 36 | this._x = x; 37 | this._y = y; 38 | this._radius = radius; 39 | } 40 | 41 | draw(){ 42 | this.drawApi.draw(this._radius, this._x, this._y); 43 | } 44 | 45 | } 46 | 47 | 48 | 49 | const redCircle = new Circle(100, 100, 10, new RedCircle()); 50 | 51 | const greenCircle = new Circle(105, 120 , 10 , new GreenCircle()); 52 | 53 | redCircle.draw(); 54 | 55 | greenCircle.draw(); -------------------------------------------------------------------------------- /src/Builder.pu: -------------------------------------------------------------------------------- 1 | @startuml 2 | scale 3 3 | title 建造者模式 4 | skinparam defaultFontName "Verdana 黑体" 5 | skinparam backgroundColor #EEEBDC 6 | 7 | interface Item { 8 | +name() : string 9 | +price(): number 10 | +packing() : Packing 11 | } 12 | 13 | interface Packing{ 14 | +pack() : string 15 | } 16 | 17 | class Wrapper 18 | 19 | class Bottle 20 | 21 | abstract class Burger 22 | 23 | abstract class ColdDrink 24 | 25 | class VegBurger 26 | 27 | class ChickenBurger 28 | 29 | class Coke 30 | 31 | class Pepsi 32 | 33 | class Meal{ 34 | _items : Item[] 35 | } 36 | 37 | class MealBuilder{ 38 | +prepareVegMeal() : Meal 39 | +prepareNotVegMeal() : Meal 40 | } 41 | 42 | Packing <|.. Wrapper 43 | Packing <|.. Bottle 44 | 45 | Burger ...|> Item 46 | ColdDrink ...|> Item 47 | 48 | Burger --* Wrapper 49 | ColdDrink --* Bottle 50 | 51 | VegBurger --|> Burger 52 | ChickenBurger --|> Burger 53 | 54 | Coke --|> ColdDrink 55 | Pepsi --|> ColdDrink 56 | 57 | Meal "1" --o "many" Item 58 | 59 | MealBuilder --o Meal 60 | 61 | ' 备注 62 | note left of Bottle 63 | 所有的饮料都用瓶子进行包装 64 | end note 65 | 66 | note right of Wrapper 67 | 所有的汉堡都用纸盒抱起来 68 | end note 69 | 70 | @enduml -------------------------------------------------------------------------------- /src/Builder.ts: -------------------------------------------------------------------------------- 1 | // 建造者模式 2 | 3 | // 从一个个简单的类组合成一个大的类。 汉堡,饮料组合成不同套餐。通过Meal创建出不同的套餐; 4 | 5 | // 食品包装接口 6 | interface Packing{ 7 | pack(): string; 8 | } 9 | 10 | // 纸质包装类,专门用来包裹汉堡 11 | class Wrapper implements Packing{ 12 | pack(){ 13 | return "Wrapper"; 14 | } 15 | } 16 | 17 | // 瓶子包裝类,专门用来装饮料 18 | class Bottle implements Packing{ 19 | pack(){ 20 | return "Bottle"; 21 | } 22 | } 23 | 24 | // 食物接口 25 | interface Item{ 26 | name():string; 27 | packing(): Packing; 28 | price(): number; 29 | } 30 | 31 | // 基类的好处,就是把公共的逻辑提取到基类中 32 | 33 | // 汉堡基类 34 | abstract class Burger implements Item{ 35 | name(){ 36 | return "Burger"; 37 | } 38 | packing() : Packing { 39 | return new Wrapper() 40 | } 41 | abstract price(): number; 42 | } 43 | 44 | // 饮料基类 45 | abstract class ColdDrink implements Item{ 46 | name(){ 47 | return "ColdDrink"; 48 | } 49 | packing() : Packing { 50 | return new Bottle() 51 | } 52 | abstract price(): number; 53 | 54 | } 55 | 56 | // 素食汉堡 57 | class VegBurger extends Burger{ 58 | name(){ 59 | return "VegBurger" 60 | } 61 | price() { 62 | return 25; 63 | } 64 | } 65 | 66 | // 鸡肉汉堡 67 | class ChickenBurger extends Burger{ 68 | price(){ 69 | return 50; 70 | } 71 | name(){ 72 | return "ChickenBurger"; 73 | } 74 | } 75 | 76 | // 可口可乐 77 | class Coke extends ColdDrink{ 78 | name(){ 79 | return "Coke"; 80 | } 81 | price(){ 82 | return 30; 83 | } 84 | } 85 | 86 | // 百事可乐 87 | 88 | class Pepsi extends ColdDrink{ 89 | name(){ 90 | return "Pepsi"; 91 | } 92 | price(){ 93 | return 35; 94 | } 95 | } 96 | 97 | // 套餐 98 | class Meal{ 99 | private _items: Item[] = []; 100 | 101 | addItem(item: Item){ 102 | this._items.push(item); 103 | } 104 | 105 | getCost(){ 106 | let cost = 0; 107 | for(let item of this._items){ 108 | cost += item.price(); 109 | } 110 | return cost; 111 | } 112 | showItems(){ 113 | for(let item of this._items){ 114 | console.log(`Item : ${item.name()}`); 115 | console.log(`Packing : ${item.packing().pack()} `); 116 | console.log(`Price : ${item.price()} \n`); 117 | } 118 | } 119 | } 120 | 121 | class MealBuilder{ 122 | // 准备素食套餐 123 | prepareVegMeal(){ 124 | let meal = new Meal(); 125 | meal.addItem(new VegBurger()); 126 | meal.addItem(new Coke()); 127 | return meal; 128 | } 129 | // 准备非素食套餐 130 | prepareNotVegMeal(){ 131 | let meal = new Meal(); 132 | meal.addItem(new ChickenBurger()) 133 | meal.addItem(new Pepsi()) 134 | return meal 135 | } 136 | } 137 | 138 | 139 | 140 | let mealBuilder = new MealBuilder(); 141 | 142 | let m1 = mealBuilder.prepareVegMeal() 143 | 144 | console.log("VegMeal :") 145 | m1.showItems() 146 | 147 | console.log("total cost = " + m1.getCost() + "\n"); 148 | 149 | console.log("***********************************\n") 150 | 151 | let m2 = mealBuilder.prepareNotVegMeal() 152 | 153 | console.log("Not-VegMeal :") 154 | m2.showItems() 155 | console.log("total cost = " + m2.getCost() + "\n"); 156 | 157 | 158 | 159 | export { 160 | Meal, 161 | MealBuilder, 162 | VegBurger, 163 | ChickenBurger, 164 | Coke, 165 | Pepsi 166 | } -------------------------------------------------------------------------------- /src/BusinessDelegate.ts: -------------------------------------------------------------------------------- 1 | 2 | // 业务服务 3 | interface BusinessService { 4 | doProcessing(); 5 | } 6 | 7 | class EJBService implements BusinessService { 8 | doProcessing() { 9 | console.log("Processing task by invoking EJB Service"); 10 | } 11 | } 12 | 13 | class JMSService implements BusinessService { 14 | doProcessing() { 15 | console.log("Processing task by invoking JMS Service"); 16 | } 17 | } 18 | 19 | // 查询服务 20 | class BusinessLookUp { 21 | public getBusinessService(serviceType: string): BusinessService{ 22 | if(serviceType.toLocaleLowerCase() === "ejb"){ 23 | return new EJBService(); 24 | }else { 25 | return new JMSService(); 26 | } 27 | } 28 | } 29 | 30 | // 业务代表 31 | class BusinessDelegate { 32 | private lookupService: BusinessLookUp = new BusinessLookUp(); 33 | private businessService: BusinessService; 34 | private serviceType: string; 35 | 36 | setServiceType(serviceType: string){ 37 | this.serviceType = serviceType; 38 | } 39 | 40 | doTask(){ 41 | this.businessService = this.lookupService.getBusinessService(this.serviceType); 42 | this.businessService.doProcessing(); 43 | } 44 | } 45 | 46 | 47 | class Client { 48 | businessService: BusinessDelegate; 49 | 50 | constructor(businessService: BusinessDelegate){ 51 | this.businessService = businessService; 52 | } 53 | 54 | doTask(){ 55 | this.businessService.doTask(); 56 | } 57 | } 58 | 59 | let businessDelegate = new BusinessDelegate(); 60 | businessDelegate.setServiceType("EJB"); 61 | 62 | let client = new Client(businessDelegate); 63 | client.doTask(); 64 | 65 | businessDelegate.setServiceType("JMS"); 66 | client.doTask(); 67 | -------------------------------------------------------------------------------- /src/ChainResponsibility.ts: -------------------------------------------------------------------------------- 1 | abstract class AbstractLogger { 2 | static INFO : number = 1; 3 | static DEBUG : number = 2; 4 | static ERROR : number = 3; 5 | 6 | protected level : number; 7 | 8 | //责任链中的下一个元素 9 | protected nextLogger : AbstractLogger; 10 | 11 | setNextLogger(nextLogger: AbstractLogger){ 12 | this.nextLogger = nextLogger; 13 | } 14 | 15 | logMessage(level: number, message: string){ 16 | if(this.level <= level){ 17 | this.write(message); 18 | } 19 | if(this.nextLogger !=null){ 20 | this.nextLogger.logMessage(level, message); 21 | } 22 | } 23 | 24 | protected abstract write(message: string); 25 | 26 | } 27 | 28 | 29 | class ConsoleLogger extends AbstractLogger { 30 | constructor(level : number){ 31 | super() 32 | this.level = level; 33 | } 34 | 35 | write(message: string) { 36 | console.log("Standard Console::Logger: " + message); 37 | } 38 | } 39 | 40 | 41 | class ErrorLogger extends AbstractLogger { 42 | 43 | constructor(level: number){ 44 | super() 45 | this.level = level; 46 | } 47 | 48 | write(message: string) { 49 | console.log("Error Console::Logger: " + message); 50 | } 51 | } 52 | 53 | 54 | class FileLogger extends AbstractLogger { 55 | 56 | constructor(level: number){ 57 | super() 58 | this.level = level; 59 | } 60 | 61 | write(message: string) { 62 | console.log("File::Logger: " + message); 63 | } 64 | } 65 | 66 | class ChainPattern{ 67 | static getChainOfLoggers() : AbstractLogger{ 68 | 69 | let errorLogger = new ErrorLogger(AbstractLogger.ERROR); 70 | let fileLogger = new FileLogger(AbstractLogger.DEBUG); 71 | let consoleLogger = new ConsoleLogger(AbstractLogger.INFO); 72 | 73 | errorLogger.setNextLogger(fileLogger); 74 | fileLogger.setNextLogger(consoleLogger); 75 | 76 | return errorLogger; 77 | } 78 | 79 | } 80 | 81 | let loggerChain = ChainPattern.getChainOfLoggers(); 82 | 83 | loggerChain.logMessage(AbstractLogger.INFO, 84 | "This is an information."); 85 | 86 | loggerChain.logMessage(AbstractLogger.DEBUG, 87 | "This is an debug level information."); 88 | 89 | loggerChain.logMessage(AbstractLogger.ERROR, 90 | "This is an error information."); -------------------------------------------------------------------------------- /src/Command.ts: -------------------------------------------------------------------------------- 1 | interface Order{ 2 | execute() 3 | } 4 | 5 | 6 | class Stock { 7 | 8 | private name: string = "ABC"; 9 | private quantity: number = 10; 10 | 11 | buy(){ 12 | console.log("Stock [ Name: "+this.name+" Quantity: " + this.quantity +" ] bought"); 13 | } 14 | sell(){ 15 | console.log("Stock [ Name: "+this.name+" Quantity: " + this.quantity +" ] sold"); 16 | } 17 | } 18 | 19 | class BuyStock implements Order { 20 | private abcStock : Stock; 21 | 22 | constructor(abcStock: Stock){ 23 | this.abcStock = abcStock; 24 | } 25 | 26 | execute() { 27 | this.abcStock.buy(); 28 | } 29 | } 30 | 31 | class SellStock implements Order { 32 | private abcStock: Stock; 33 | 34 | constructor(abcStock: Stock){ 35 | this.abcStock = abcStock; 36 | } 37 | 38 | execute() { 39 | this.abcStock.sell(); 40 | } 41 | } 42 | 43 | class Broker { 44 | private orderList = new Array(); 45 | 46 | takeOrder(order: Order){ 47 | this.orderList.push(order); 48 | } 49 | 50 | placeOrders(){ 51 | for (let order of this.orderList) { 52 | order.execute(); 53 | } 54 | this.orderList.length = 0; 55 | } 56 | } 57 | 58 | let abcStock = new Stock(); 59 | 60 | let buyStockOrder = new BuyStock(abcStock); 61 | let sellStockOrder = new SellStock(abcStock); 62 | 63 | let brock = new Broker(); 64 | 65 | brock.takeOrder(buyStockOrder); 66 | brock.takeOrder(sellStockOrder); 67 | 68 | brock.placeOrders() 69 | -------------------------------------------------------------------------------- /src/Composite.ts: -------------------------------------------------------------------------------- 1 | class Employee{ 2 | name: string; 3 | dept: string; 4 | salary: number; 5 | 6 | subordinates: Employee[] = new Array(); 7 | 8 | constructor(name: string, dept: string, sal: number){ 9 | this.name = name; 10 | this.dept = dept; 11 | this.salary = sal; 12 | } 13 | 14 | add(e: Employee){ 15 | this.subordinates.push(e); 16 | } 17 | 18 | remove(e: Employee){ 19 | let index = this.subordinates.findIndex( item => item == e) 20 | if(index){ 21 | this.subordinates.splice(index, 1); 22 | } 23 | } 24 | 25 | toString(){ 26 | return ("Employee :[ Name : "+ this.name +", dept : "+ this.dept + ", salary :"+ this.salary+" ] \n"); 27 | } 28 | } 29 | 30 | let CEO = new Employee("John","CEO", 30000); 31 | 32 | let headSales = new Employee("Robert","Head Sales", 20000); 33 | 34 | let headMarketing = new Employee("Michel","Head Marketing", 20000); 35 | 36 | let clerk1 = new Employee("Laura","Marketing", 10000); 37 | let clerk2 = new Employee("Bob","Marketing", 10000); 38 | 39 | let salesExecutive1 = new Employee("Richard","Sales", 10000); 40 | let salesExecutive2 = new Employee("Rob","Sales", 10000); 41 | 42 | CEO.add(headSales); 43 | CEO.add(headMarketing); 44 | 45 | headSales.add(salesExecutive1); 46 | headSales.add(salesExecutive2); 47 | 48 | headMarketing.add(clerk1); 49 | headMarketing.add(clerk2); 50 | 51 | for(let person of CEO.subordinates){ 52 | console.log(person); 53 | for(let nextPerson of person.subordinates){ 54 | console.log(" \t " + nextPerson); 55 | } 56 | } -------------------------------------------------------------------------------- /src/CompositeEntity.ts: -------------------------------------------------------------------------------- 1 | namespace CompositeEntity{ 2 | 3 | class DependentObject1 { 4 | 5 | private data: string; 6 | 7 | setData(data: string){ 8 | this.data = data; 9 | } 10 | 11 | getData(){ 12 | return this.data; 13 | } 14 | } 15 | 16 | class DependentObject2 { 17 | 18 | private data: string; 19 | 20 | setData(data: string){ 21 | this.data = data; 22 | } 23 | 24 | getData(){ 25 | return this.data; 26 | } 27 | } 28 | 29 | class CoarseGrainedObject { 30 | do1 = new DependentObject1(); 31 | do2 = new DependentObject2(); 32 | 33 | setData(data1: string, data2: string){ 34 | this.do1.setData(data1); 35 | this.do2.setData(data2); 36 | } 37 | 38 | getData(){ 39 | return [this.do1.getData(), this.do2.getData()]; 40 | } 41 | } 42 | 43 | class CompositeEntity { 44 | private cgo = new CoarseGrainedObject(); 45 | 46 | setData(data1: string, data2: string){ 47 | this.cgo.setData(data1, data2); 48 | } 49 | 50 | getData(){ 51 | return this.cgo.getData(); 52 | } 53 | } 54 | 55 | 56 | class Client { 57 | private compositeEntity = new CompositeEntity(); 58 | 59 | printData(){ 60 | for (let i = 0; i < this.compositeEntity.getData().length; i++) { 61 | console.log("Data: " + this.compositeEntity.getData()[i]); 62 | } 63 | } 64 | 65 | setData(data1: string, data2: string){ 66 | this.compositeEntity.setData(data1, data2); 67 | } 68 | } 69 | 70 | let client = new Client(); 71 | client.setData("Test", "Data"); 72 | client.printData(); 73 | client.setData("Second Test", "Data1"); 74 | client.printData(); 75 | } 76 | -------------------------------------------------------------------------------- /src/DataAccessObject.ts: -------------------------------------------------------------------------------- 1 | namespace DataAccessObject{ 2 | class Student { 3 | private name: string; 4 | private rollNo: number; 5 | 6 | constructor(name: string,rollNo: number){ 7 | this.name = name; 8 | this.rollNo = rollNo; 9 | } 10 | 11 | getName(): string { 12 | return this.name; 13 | } 14 | 15 | setName(name: string) { 16 | this.name = name; 17 | } 18 | 19 | getRollNo(): number { 20 | return this.rollNo; 21 | } 22 | 23 | setRollNo(rollNo: number) { 24 | this.rollNo = rollNo; 25 | } 26 | } 27 | 28 | interface StudentDao { 29 | getAllStudents() : Array ; 30 | getStudent(rollNo: number): Student; 31 | updateStudent(student: Student); 32 | deleteStudent(student: Student); 33 | } 34 | 35 | class StudentDaoImpl implements StudentDao { 36 | 37 | students: Array; 38 | 39 | constructor(){ 40 | this.students = new Array(); 41 | let student1 = new Student("Robert",0); 42 | let student2 = new Student("John",1); 43 | this.students.push(student1); 44 | this.students.push(student2); 45 | } 46 | 47 | deleteStudent(student: Student) { 48 | this.students.splice(student.getRollNo(), 1); 49 | console.log("Student: Roll No " + student.getRollNo() 50 | +", deleted from database"); 51 | } 52 | 53 | //从数据库中检索学生名单 54 | getAllStudents(): Student[] { 55 | return this.students; 56 | } 57 | 58 | getStudent(rollNo: number) { 59 | return this.students[rollNo]; 60 | } 61 | 62 | updateStudent(student: Student) { 63 | this.students[student.getRollNo()].setName(student.getName()); 64 | console.log("Student: Roll No " + student.getRollNo() 65 | +", updated in the database"); 66 | } 67 | } 68 | 69 | let studentDao = new StudentDaoImpl(); 70 | 71 | //输出所有的学生 72 | for (let student of studentDao.getAllStudents()) { 73 | console.log("Student: [RollNo : " 74 | +student.getRollNo()+", Name : "+student.getName()+" ]"); 75 | } 76 | 77 | 78 | //更新学生 79 | let student = studentDao.getAllStudents()[0]; 80 | student.setName("Michael"); 81 | studentDao.updateStudent(student); 82 | 83 | //获取学生 84 | studentDao.getStudent(0); 85 | console.log("Student: [RollNo : " 86 | +student.getRollNo()+", Name : "+student.getName()+" ]"); 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/Decorator.ts: -------------------------------------------------------------------------------- 1 | namespace Decorator{ 2 | interface Shape{ 3 | draw() : void; 4 | } 5 | 6 | 7 | class Rectangle implements Shape{ 8 | draw(){ 9 | console.log("Rectangle") 10 | } 11 | } 12 | 13 | class Circle implements Shape{ 14 | draw(){ 15 | console.log("Circle"); 16 | } 17 | } 18 | 19 | abstract class ShapeDecorator implements Shape{ 20 | 21 | constructor(protected decoratedShape: Shape){} 22 | 23 | draw(){ 24 | this.decoratedShape.draw() 25 | } 26 | } 27 | 28 | class RedShapeDecorator extends ShapeDecorator { 29 | 30 | constructor(decoratedShape : Shape) { 31 | super(decoratedShape); 32 | } 33 | 34 | draw() { 35 | this.decoratedShape.draw(); 36 | this.setRedBorder(this.decoratedShape); // 后置的装饰器 37 | } 38 | 39 | private setRedBorder( decoratedShape: Shape){ 40 | console.log("Border Color: Red"); 41 | } 42 | } 43 | 44 | 45 | let circle = new Circle(); 46 | 47 | let redCircle = new RedShapeDecorator(new Circle()); 48 | 49 | let redRectangle = new RedShapeDecorator(new Rectangle()); 50 | console.log("Circle with normal border"); 51 | circle.draw(); 52 | 53 | console.log("\nCircle of red border"); 54 | redCircle.draw(); 55 | 56 | console.log("\nRectangle of red border"); 57 | redRectangle.draw(); 58 | 59 | 60 | 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/Facade.ts: -------------------------------------------------------------------------------- 1 | namespace Facade{ 2 | interface Shape{ 3 | draw(); 4 | } 5 | 6 | class Rectangle implements Shape{ 7 | draw(){ 8 | console.log(this); 9 | } 10 | } 11 | 12 | class Square implements Shape{ 13 | draw(){ 14 | console.log(Object.getPrototypeOf(this).name); 15 | } 16 | } 17 | 18 | class Circle implements Shape { 19 | draw() { 20 | console.log("Circle::draw()"); 21 | } 22 | } 23 | 24 | class ShapleMaker{ 25 | private circle: Circle; 26 | private rectangle : Rectangle; 27 | private square : Square; 28 | 29 | constructor(){ 30 | this.circle = new Circle(); 31 | this.rectangle = new Rectangle(); 32 | this.square = new Square() 33 | } 34 | 35 | drawCircle(){ 36 | this.circle.draw(); 37 | } 38 | 39 | drawRectangle(){ 40 | this.rectangle.draw(); 41 | } 42 | 43 | drawSquare(){ 44 | this.square.draw() 45 | } 46 | } 47 | 48 | 49 | let sm = new ShapleMaker(); 50 | sm.drawCircle(); 51 | sm.drawRectangle(); 52 | sm.drawSquare(); 53 | 54 | 55 | } -------------------------------------------------------------------------------- /src/Factory.pu: -------------------------------------------------------------------------------- 1 | @startuml 2 | scale 3 3 | title 工厂模式 4 | skinparam defaultFontName "Verdana 黑体" 5 | skinparam backgroundColor #EEEBDC 6 | 7 | class Mother{ 8 | + {static} giveMe(whatYouWant: string) : Jelly | null 9 | + {static} chewJelly(jelly : Jelly) : jelly 10 | } 11 | 12 | 13 | class Jelly 14 | class ToyPlane 15 | 16 | 17 | Mother o.. Jelly 18 | Mother o.. ToyPlane 19 | 20 | 21 | @enduml -------------------------------------------------------------------------------- /src/Factory.ts: -------------------------------------------------------------------------------- 1 | // 妈妈类 2 | class Mother { 3 | // 向妈妈申请所有你想要的 4 | static giveMe(whatYouWant){ 5 | switch(whatYouWant){ 6 | // 糖糖 7 | case "tangtang": 8 | console.log("宝宝,你一个人吃果冻是非常危险的哦,妈妈喂你~~"); 9 | return Mother.chewJelly(new Jelly); 10 | // 飞飞 11 | case "feifei": 12 | console.log("宝宝,家里已经买了很多飞机了哦,") 13 | return null; 14 | default: return null; 15 | } 16 | } 17 | 18 | static chewJelly(jelly){ 19 | jelly.chewed = true; 20 | return jelly; 21 | } 22 | } 23 | 24 | // 果冻类 25 | class Jelly{ 26 | // 是否咀嚼过的果冻 27 | chewed = false; 28 | } 29 | 30 | // 玩具飞机 31 | class ToyPlane {} 32 | 33 | 34 | 35 | // console.log(`///////////////////// 分割线 /////////////////////////`); 36 | 37 | 38 | // 正则工厂 39 | function fieldTest(fieldName){ 40 | switch(fieldName){ 41 | case 'phone': 42 | return /^1[3|4|5|8][0-9]\d{4,8}$/; 43 | case 'email': 44 | return /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/; 45 | case 'character': // 是否为汉字 46 | return /^[\u4e00-\u9fa5]{0,}$/; 47 | } 48 | } 49 | 50 | 51 | // console.log(`///////////////////// 分割线 /////////////////////////`); 52 | 53 | 54 | function XiaoMi(factoryName): any{ 55 | switch(factoryName){ 56 | case 'battery': return MobileBatteryFactory; 57 | case 'screen': return MobileScreenFactory; 58 | } 59 | } 60 | 61 | class Battery{}; 62 | 63 | class MobileBatteryFactory { 64 | static getBattery(): Battery { 65 | return new Battery(); 66 | } 67 | } 68 | 69 | class MobileScreenFactory { 70 | static getScreen(){ 71 | return { name: 'screen' } 72 | } 73 | } 74 | 75 | 76 | // console.log(`///////////////////// 分割线 /////////////////////////`); 77 | 78 | class AllFactory { 79 | static getFieldTest = () => fieldTest; 80 | static getMother = () => Mother 81 | } 82 | 83 | 84 | export { 85 | Mother, 86 | Jelly, 87 | ToyPlane, 88 | fieldTest, 89 | XiaoMi, 90 | Battery, 91 | MobileBatteryFactory, 92 | MobileScreenFactory, 93 | AllFactory 94 | 95 | } -------------------------------------------------------------------------------- /src/Filter.ts: -------------------------------------------------------------------------------- 1 | class Person{ 2 | constructor(public name: string, public gender: string, public maritalStatus: string){} 3 | } 4 | 5 | 6 | interface Criteria{ 7 | meetCriteria(persons: Person[]) 8 | } 9 | 10 | 11 | class CriteriaMale implements Criteria { 12 | meetCriteria(persons: Person[]){ 13 | return persons.filter((Person) => Person.gender.toLowerCase() == 'male'); 14 | } 15 | } 16 | 17 | class CriteriaFemale implements Criteria{ 18 | meetCriteria(persons: Person[]){ 19 | return persons.filter((Person) => Person.gender.toLowerCase() == 'female'); 20 | } 21 | } 22 | 23 | class CriteriaSingle implements Criteria{ 24 | meetCriteria(persons: Person[]){ 25 | return persons.filter((Person) => Person.maritalStatus.toLowerCase() == 'single'); 26 | } 27 | } 28 | 29 | class AndCriteria implements Criteria{ 30 | constructor(public criteria: Criteria, public otherCriteria: Criteria){} 31 | 32 | meetCriteria(persons: Person[]){ 33 | let firstCriteriaPersons = this.criteria.meetCriteria(persons); 34 | return this.otherCriteria.meetCriteria(firstCriteriaPersons); 35 | } 36 | } 37 | 38 | class OrCriteria implements Criteria{ 39 | constructor(public criteria: Criteria, public otherCriteria: Criteria){} 40 | 41 | meetCriteria(persons: Person[]){ 42 | let firstCriteriaPersons = this.criteria.meetCriteria(persons); 43 | let secondCriteriaPersons = this.otherCriteria.meetCriteria(firstCriteriaPersons); 44 | 45 | firstCriteriaPersons.forEach((person) => { 46 | if(!secondCriteriaPersons.find(p => p === person)){ // 假如 person 不在 secondCriteriaPersons 中 47 | secondCriteriaPersons.push(person); 48 | } 49 | }); 50 | 51 | return secondCriteriaPersons; 52 | } 53 | } 54 | 55 | 56 | let persons = new Array(); 57 | 58 | persons.push(new Person('Robert', 'Male', 'Single')); 59 | persons.push(new Person("John", "Male", "Married")); 60 | persons.push(new Person('Laura','Female','Married')); 61 | persons.push(new Person("Diana", "Female", "Single")); 62 | persons.push(new Person("Mike","Male","Single")); 63 | persons.push(new Person("Boggy","Male","Single")); 64 | 65 | let male = new CriteriaMale(); 66 | let female = new CriteriaFemale(); 67 | let single = new CriteriaSingle(); 68 | 69 | let singleMale = new AndCriteria(single, male); 70 | let singleOrFemal = new OrCriteria(single, female); 71 | 72 | 73 | function getFilter(propName : keyof Person, key: string){ 74 | return (persons: Person[]) => { 75 | return persons.filter(p => (p[propName] as string).toLocaleLowerCase() == key) 76 | } 77 | } 78 | 79 | let femaleFilter = getFilter("gender", "female"); 80 | 81 | function maleFilter(persons : Person[]){ 82 | return persons.filter(p => p.gender.toLocaleLowerCase() == 'male') 83 | } 84 | 85 | console.log(male.meetCriteria(persons)); 86 | 87 | console.log(maleFilter(persons)); 88 | 89 | console.log(female.meetCriteria(persons)); 90 | 91 | console.log(femaleFilter(persons)); 92 | 93 | console.log(singleMale.meetCriteria(persons)); 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /src/Flyweight.ts: -------------------------------------------------------------------------------- 1 | namespace Flyweight{ 2 | interface Shape{draw()} 3 | 4 | class Circle implements Shape{ 5 | color: string; 6 | x: number; 7 | y: number; 8 | radius: number; 9 | 10 | constructor(color: string){ 11 | this.color = color; 12 | } 13 | 14 | draw(){ 15 | console.log(this); 16 | } 17 | 18 | 19 | } 20 | 21 | class ShapeFactory{ 22 | private static cache = new Map(); 23 | 24 | static getShape(color: string){ 25 | let circle = this.cache.get(color); 26 | 27 | if(circle == null){ 28 | circle = new Circle(color); 29 | this.cache.set(color, circle); 30 | } 31 | return circle; 32 | } 33 | } 34 | 35 | 36 | let colors = ["Red", "Green", "Blue", "White", "Black" ] 37 | 38 | function getRandomColor(){ 39 | return colors[Math.random() * colors.length] 40 | } 41 | 42 | function getRandomX(){ 43 | return Math.random() * 100; 44 | } 45 | 46 | function getRandomY(){ 47 | return Math.random() * 100; 48 | } 49 | 50 | colors.forEach(color => { 51 | let circle = ShapeFactory.getShape(color); 52 | circle.x = getRandomX(); 53 | circle.y = getRandomY(); 54 | circle.radius = 100; 55 | circle.draw(); 56 | }) 57 | 58 | 59 | } -------------------------------------------------------------------------------- /src/FrontController.ts: -------------------------------------------------------------------------------- 1 | namespace FrontController{ 2 | class HomeView { 3 | show(){ 4 | console.log("Displaying Home Page"); 5 | } 6 | } 7 | 8 | class StudentView { 9 | show(){ 10 | console.log("Displaying Student Page"); 11 | } 12 | } 13 | 14 | class Dispatcher { 15 | private studentView: StudentView; 16 | private homeView: HomeView; 17 | constructor(){ 18 | this.studentView = new StudentView(); 19 | this.homeView = new HomeView(); 20 | } 21 | 22 | dispatch(request: string){ 23 | if(request.toLocaleUpperCase() === "STUDENT"){ 24 | this.studentView.show(); 25 | } else { 26 | this.homeView.show(); 27 | } 28 | } 29 | } 30 | 31 | class FrontController { 32 | 33 | private dispatcher: Dispatcher; 34 | 35 | constructor(){ 36 | this.dispatcher = new Dispatcher(); 37 | } 38 | 39 | private isAuthenticUser(): boolean{ 40 | console.log("User is authenticated successfully."); 41 | return true; 42 | } 43 | 44 | private trackRequest(request: string){ 45 | console.log("Page requested: " + request); 46 | } 47 | 48 | public dispatchRequest(request: string){ 49 | //记录每一个请求 50 | this.trackRequest(request); 51 | //对用户进行身份验证 52 | if(this.isAuthenticUser()){ 53 | this.dispatcher.dispatch(request); 54 | } 55 | } 56 | } 57 | 58 | let frontController = new FrontController(); 59 | frontController.dispatchRequest("HOME"); 60 | console.log("==============="); 61 | frontController.dispatchRequest("STUDENT"); 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/InterceptingFilter.ts: -------------------------------------------------------------------------------- 1 | // 过滤器(Filter) - 过滤器在请求处理程序执行请求之前或之后,执行某些任务。 2 | // 过滤器链(Filter Chain) - 过滤器链带有多个过滤器,并在 Target 上按照定义的顺序执行这些过滤器。 3 | // Target - Target 对象是请求处理程序。 4 | // 过滤管理器(Filter Manager) - 过滤管理器管理过滤器和过滤器链。 5 | // 客户端(Client) - Client 是向 Target 对象发送请求的对象。 6 | 7 | namespace InterceptingFilter{ 8 | 9 | interface Filter { 10 | execute(request: string); 11 | } 12 | 13 | class AuthenticationFilter implements Filter { 14 | execute(request: string){ 15 | console.log("Authenticating request: " + request); 16 | } 17 | } 18 | 19 | class DebugFilter implements Filter { 20 | execute(request: string){ 21 | console.log("request log: " + request); 22 | } 23 | } 24 | 25 | // 真正要执行的操作 26 | class Target { 27 | execute(request: string){ 28 | console.log("Executing request: " + request); 29 | } 30 | } 31 | 32 | class FilterChain { 33 | private filters = new Array(); 34 | private target: Target; 35 | 36 | addFilter(filter: Filter){ 37 | this.filters.push(filter); 38 | } 39 | 40 | execute(request: string){ 41 | for (let filter of this.filters) { 42 | filter.execute(request); 43 | } 44 | this.target.execute(request); 45 | } 46 | 47 | setTarget(target: Target){ 48 | this.target = target; 49 | } 50 | } 51 | 52 | 53 | class FilterManager { 54 | filterChain: FilterChain; 55 | 56 | constructor(target: Target){ 57 | this.filterChain = new FilterChain(); 58 | this.filterChain.setTarget(target); 59 | } 60 | setFilter(filter: Filter){ 61 | this.filterChain.addFilter(filter); 62 | } 63 | 64 | filterRequest(request: string){ 65 | this.filterChain.execute(request); 66 | } 67 | } 68 | 69 | class Client { 70 | filterManager: FilterManager; 71 | 72 | setFilterManager(filterManager: FilterManager){ 73 | this.filterManager = filterManager; 74 | } 75 | 76 | sendRequest(request: string){ 77 | filterManager.filterRequest(request); 78 | } 79 | } 80 | 81 | let filterManager = new FilterManager(new Target()); 82 | filterManager.setFilter(new AuthenticationFilter()); 83 | filterManager.setFilter(new DebugFilter()); 84 | 85 | let client = new Client(); 86 | client.setFilterManager(filterManager); 87 | client.sendRequest("HOME"); 88 | 89 | } -------------------------------------------------------------------------------- /src/Interpreter.ts: -------------------------------------------------------------------------------- 1 | interface Expression { 2 | interpret(context: string) : boolean; 3 | } 4 | 5 | class TerminalExpression implements Expression { 6 | private data: string; 7 | constructor(data: string){ 8 | this.data = data; 9 | } 10 | 11 | interpret(context: string): boolean { 12 | if(context.indexOf(this.data) >= 0){ 13 | return true; 14 | } 15 | return false; 16 | } 17 | } 18 | 19 | class OrExpression implements Expression { 20 | private expr1 : Expression = null; 21 | private expr2 : Expression = null; 22 | constructor(expr1: Expression, expr2: Expression){ 23 | this.expr1 = expr1; 24 | this.expr2 = expr2; 25 | } 26 | 27 | interpret(context: string): boolean { 28 | return this.expr1.interpret(context) || this.expr2.interpret(context); 29 | } 30 | } 31 | 32 | 33 | class AndExpression implements Expression { 34 | private expr1 : Expression = null; 35 | private expr2 : Expression = null; 36 | constructor(expr1: Expression, expr2: Expression){ 37 | this.expr1 = expr1; 38 | this.expr2 = expr2; 39 | } 40 | 41 | interpret(context: string): boolean { 42 | return this.expr1.interpret(context) && this.expr2.interpret(context); 43 | } 44 | } 45 | 46 | function getMaleExpression(){ 47 | let robert = new TerminalExpression("Robert"); 48 | let john = new TerminalExpression("John"); 49 | return new OrExpression(robert, john); 50 | } 51 | function getMarriedWomanExpression(){ 52 | let julie = new TerminalExpression("Julie"); 53 | let married = new TerminalExpression("Married"); 54 | return new AndExpression(julie, married); 55 | } 56 | 57 | let isMale = getMaleExpression(); 58 | let isMarriedWoman = getMarriedWomanExpression(); 59 | 60 | console.log("John is male? " + isMale.interpret("John")); 61 | console.log("Julie is a married women? " 62 | + isMarriedWoman.interpret("Married Julie")); -------------------------------------------------------------------------------- /src/Iterator.ts: -------------------------------------------------------------------------------- 1 | 2 | namespace Iterator{ 3 | interface Iterator{ 4 | hasNext(): boolean; 5 | next(): any; 6 | } 7 | 8 | interface Container{ 9 | getIterator(): Iterator; 10 | } 11 | 12 | class NameIterator implements Iterator{ 13 | 14 | index: number = 0; 15 | names = ["Robert" , "John" ,"Julie" , "Lora"]; 16 | hasNext() { 17 | if(this.index < this.names.length){ 18 | return true; 19 | } 20 | return false; 21 | } 22 | 23 | next() { 24 | if(this.hasNext()){ 25 | return this.names[this.index++]; 26 | } 27 | return null; 28 | } 29 | } 30 | 31 | class NameRepository implements Container{ 32 | getIterator(): Iterator{ 33 | return new NameIterator(); 34 | } 35 | } 36 | 37 | let namesRepository = new NameRepository(); 38 | 39 | for(let iter = namesRepository.getIterator();iter.hasNext();){ 40 | let name = iter.next(); 41 | console.log("Name : " + name); 42 | } 43 | 44 | } 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/MVC.ts: -------------------------------------------------------------------------------- 1 | class Student { 2 | private rollNo: string; 3 | private name: string; 4 | getRollNo(): string { 5 | return this.rollNo; 6 | } 7 | setRollNo(rollNo: string) { 8 | this.rollNo = rollNo; 9 | } 10 | getName(): string { 11 | return this.name; 12 | } 13 | setName(name: string) { 14 | this.name = name; 15 | } 16 | } 17 | 18 | class StudentView { 19 | printStudentDetails(studentName: string,studentRollNo: string){ 20 | console.log("Student: "); 21 | console.log("Name: " + studentName); 22 | console.log("Roll No: " + studentRollNo); 23 | } 24 | } 25 | 26 | class StudentController { 27 | private model: Student; 28 | private view: StudentView; 29 | 30 | constructor(model: Student,view: StudentView){ 31 | this.model = model; 32 | this.view = view; 33 | } 34 | 35 | setStudentName(name: string){ 36 | this.model.setName(name); 37 | } 38 | 39 | getStudentName(){ 40 | return this.model.getName(); 41 | } 42 | 43 | setStudentRollNo(rollNo: string){ 44 | this.model.setRollNo(rollNo); 45 | } 46 | 47 | getStudentRollNo(): string{ 48 | return this.model.getRollNo(); 49 | } 50 | 51 | updateView(){ 52 | this.view.printStudentDetails(this.model.getName(), this.model.getRollNo()); 53 | } 54 | } 55 | 56 | function retriveStudentFromDatabase(){ 57 | let student = new Student(); 58 | student.setName("Robert"); 59 | student.setRollNo("10"); 60 | return student; 61 | } 62 | 63 | //从数据可获取学生记录 64 | let model = retriveStudentFromDatabase(); 65 | 66 | //创建一个视图:把学生详细信息输出到控制台 67 | let view = new StudentView(); 68 | 69 | let controller = new StudentController(model, view); 70 | 71 | controller.updateView(); 72 | 73 | //更新模型数据 74 | controller.setStudentName("John"); 75 | 76 | controller.updateView(); 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/Mediator.ts: -------------------------------------------------------------------------------- 1 | class ChatRoom { 2 | static showMessage(user: User, message: string){ 3 | console.log(new Date().toString() 4 | + " [" + user.getName() +"] : " + message); 5 | } 6 | } 7 | 8 | class User { 9 | private name : string; 10 | 11 | public getName(): string { 12 | return this.name; 13 | } 14 | 15 | setName(name: string): void { 16 | this.name = name; 17 | } 18 | 19 | constructor(name: string){ 20 | this.name = name; 21 | } 22 | 23 | sendMessage(message: string): void{ 24 | ChatRoom.showMessage(this, message); 25 | } 26 | } 27 | 28 | let robert = new User("Robert"); 29 | let john = new User("John"); 30 | 31 | robert.sendMessage("Hi! John!"); 32 | john.sendMessage("Hello! Robert!"); -------------------------------------------------------------------------------- /src/Memento.ts: -------------------------------------------------------------------------------- 1 | class Memento { 2 | private state: string; 3 | 4 | constructor(state: string){ 5 | this.state = state; 6 | } 7 | 8 | getState(): string{ 9 | return this.state; 10 | } 11 | } 12 | 13 | class Originator { 14 | private state: string; 15 | 16 | setState(state: string){ 17 | this.state = state; 18 | } 19 | 20 | getState(): string{ 21 | return this.state; 22 | } 23 | 24 | saveStateToMemento(): Memento{ 25 | return new Memento(this.state); 26 | } 27 | 28 | getStateFromMemento(Memento: Memento ){ 29 | this.state = Memento.getState(); 30 | } 31 | } 32 | 33 | class CareTaker { 34 | private mementoList = new Array(); 35 | 36 | add(state: Memento){ 37 | this.mementoList.push(state); 38 | } 39 | 40 | get(index: number): Memento{ 41 | return this.mementoList[index]; 42 | } 43 | } 44 | 45 | 46 | let originator = new Originator(); 47 | let careTaker = new CareTaker(); 48 | originator.setState("State #1"); 49 | originator.setState("State #2"); 50 | careTaker.add(originator.saveStateToMemento()); // #2 51 | originator.setState("State #3"); 52 | careTaker.add(originator.saveStateToMemento()); // #3 53 | originator.setState("State #4"); 54 | 55 | console.log("Current State: " + originator.getState()); // #4 56 | originator.getStateFromMemento(careTaker.get(0)); // #2 57 | console.log("First saved State: " + originator.getState()); // #2 58 | originator.getStateFromMemento(careTaker.get(1)); // #3 59 | console.log("Second saved State: " + originator.getState()); // #3 -------------------------------------------------------------------------------- /src/NullObject.ts: -------------------------------------------------------------------------------- 1 | abstract class AbstractCustomer { 2 | protected name: string; 3 | abstract isNil(): boolean; 4 | abstract getName(): string; 5 | } 6 | 7 | class RealCustomer extends AbstractCustomer { 8 | 9 | constructor(name: string) { 10 | super(); 11 | this.name = name; 12 | } 13 | 14 | getName(): string { 15 | return this.name; 16 | } 17 | 18 | isNil(): boolean { 19 | return false; 20 | } 21 | } 22 | 23 | class NullCustomer extends AbstractCustomer { 24 | 25 | getName(): string { 26 | return "Not Available in Customer Database"; 27 | } 28 | 29 | isNil(): boolean { 30 | return true; 31 | } 32 | } 33 | 34 | class CustomerFactory { 35 | 36 | public static names = ["Rob", "Joe", "Julie"]; 37 | 38 | public static getCustomer(name: string): AbstractCustomer{ 39 | for (let i = 0; i < CustomerFactory.names.length; i++) { 40 | if (CustomerFactory.names[i].toLocaleLowerCase() == name.toLocaleLowerCase()){ 41 | return new RealCustomer(name); 42 | } 43 | } 44 | return new NullCustomer(); 45 | } 46 | } 47 | 48 | 49 | let customer1 = CustomerFactory.getCustomer("Rob"); 50 | let customer2 = CustomerFactory.getCustomer("Bob"); 51 | let customer3 = CustomerFactory.getCustomer("Julie"); 52 | let customer4 = CustomerFactory.getCustomer("Laura"); 53 | 54 | console.log("Customers"); 55 | console.log(customer1.getName()); 56 | console.log(customer2.getName()); 57 | console.log(customer3.getName()); 58 | console.log(customer4.getName()); -------------------------------------------------------------------------------- /src/Observer.ts: -------------------------------------------------------------------------------- 1 | class Subject { 2 | private observers : Observer[] = new Array(); 3 | private state: number; 4 | 5 | public getState(): number { 6 | return this.state; 7 | } 8 | 9 | public setState(state: number) { 10 | this.state = state; 11 | this.notifyAllObservers(); 12 | } 13 | 14 | attach(observer: Observer){ 15 | this.observers.push(observer); 16 | } 17 | 18 | notifyAllObservers(){ 19 | for (let observer of this.observers) { 20 | observer.update(); 21 | } 22 | } 23 | } 24 | 25 | 26 | abstract class Observer { 27 | protected subject: Subject; 28 | public abstract update(); 29 | } 30 | 31 | class BinaryObserver extends Observer{ 32 | 33 | constructor(subject: Subject){ 34 | super(); 35 | this.subject = subject; 36 | this.subject.attach(this); 37 | } 38 | 39 | update() { 40 | console.log( "Binary String: " 41 | + this.subject.getState().toString(2) ); 42 | } 43 | } 44 | 45 | class OctalObserver extends Observer{ 46 | 47 | constructor(subject: Subject){ 48 | super(); 49 | this.subject = subject; 50 | this.subject.attach(this); 51 | } 52 | 53 | update() { 54 | console.log( "Octal String: " 55 | + this.subject.getState().toString(8) ); 56 | } 57 | } 58 | 59 | class HexaObserver extends Observer{ 60 | 61 | constructor(subject: Subject){ 62 | super(); 63 | this.subject = subject; 64 | this.subject.attach(this); 65 | } 66 | 67 | update() { 68 | console.log( "Hexa String: " 69 | + this.subject.getState().toString(16) ); 70 | } 71 | } 72 | 73 | let subject = new Subject(); 74 | 75 | new HexaObserver(subject); 76 | new OctalObserver(subject); 77 | new BinaryObserver(subject); 78 | 79 | console.log("First state change: 15"); 80 | subject.setState(15); 81 | console.log("Second state change: 10"); 82 | subject.setState(10); -------------------------------------------------------------------------------- /src/Prototype.ts: -------------------------------------------------------------------------------- 1 | 2 | namespace Prototype { 3 | // 浅拷贝 4 | export abstract class Shape { 5 | private _id: string; 6 | protected type: string; 7 | 8 | setId(id: string){ 9 | this._id = id; 10 | } 11 | 12 | getId(){ 13 | return this._id; 14 | } 15 | 16 | abstract draw(); 17 | 18 | clone() : Shape { 19 | // return Object.create(this); 20 | let obj : any = {}; 21 | for(let prop in this){ 22 | console.log(prop); 23 | obj[prop] = this[prop] 24 | } 25 | obj.__proto__ = Reflect.getPrototypeOf(this); 26 | return obj; 27 | } 28 | } 29 | 30 | 31 | class Rectangle extends Shape{ 32 | type = "Rectangle"; 33 | 34 | draw(){ 35 | console.log('Rectangle draw!'); 36 | } 37 | } 38 | 39 | class Square extends Shape{ 40 | type = "Square" 41 | draw(){ 42 | console.log("Square"); 43 | } 44 | } 45 | 46 | class Circle extends Shape{ 47 | type = "Circle"; 48 | draw(){ 49 | console.log("Circle"); 50 | } 51 | } 52 | 53 | 54 | export class ShapeCache{ 55 | private static map : Map = new Map(); 56 | 57 | static getShape(id: string) : Shape | null{ 58 | if(ShapeCache.map.has(id)){ 59 | return ShapeCache.map.get(id).clone() 60 | } 61 | return null; 62 | } 63 | 64 | static loadCache(){ 65 | let circle = new Circle(); 66 | circle.setId("1"); 67 | ShapeCache.map.set(circle.getId(), circle); 68 | 69 | let square = new Square(); 70 | square.setId("2"); 71 | ShapeCache.map.set(square.getId(), square); 72 | 73 | let rectangle = new Rectangle(); 74 | rectangle.setId("3"); 75 | ShapeCache.map.set(rectangle.getId(), rectangle); 76 | } 77 | } 78 | 79 | } 80 | 81 | 82 | Prototype.ShapeCache.loadCache(); 83 | 84 | let a : Prototype.Shape = Prototype.ShapeCache.getShape("1"); 85 | 86 | console.log(JSON.stringify(a)) 87 | 88 | console.log(a.getId()) 89 | a.draw() 90 | -------------------------------------------------------------------------------- /src/Proxy.ts: -------------------------------------------------------------------------------- 1 | interface Image { 2 | display(); 3 | } 4 | 5 | class RealImage implements Image { 6 | fileName: string; 7 | 8 | constructor(fileName: string){ 9 | this.fileName = fileName; 10 | this.loadFromDisk(fileName); 11 | } 12 | 13 | display() { 14 | console.log("Displaying " + this.fileName); 15 | } 16 | 17 | loadFromDisk(fileName: string){ 18 | console.log("Loading " + fileName); 19 | } 20 | } 21 | 22 | class ProxyImage implements Image{ 23 | 24 | realImage : RealImage; 25 | fileName : string; 26 | 27 | constructor(fileName: string){ 28 | this.fileName = fileName; 29 | } 30 | 31 | display() { 32 | if(this.realImage == null){ 33 | this.realImage = new RealImage(this.fileName); 34 | } 35 | this.realImage.display(); 36 | } 37 | } 38 | 39 | 40 | let img = new ProxyImage('A.png'); 41 | img.display(); -------------------------------------------------------------------------------- /src/ServiceLocator.ts: -------------------------------------------------------------------------------- 1 | // 服务(Service) - 实际处理请求的服务。对这种服务的引用可以在 JNDI 服务器中查找到。 2 | // Context / 初始的 Context - JNDI Context 带有对要查找的服务的引用。 3 | // 服务定位器(Service Locator) - 服务定位器是通过 JNDI 查找和缓存服务来获取服务的单点接触。 4 | // 缓存(Cache) - 缓存存储服务的引用,以便复用它们。 5 | // 客户端(Client) - Client 是通过 ServiceLocator 调用服务的对象。 6 | 7 | interface Service { 8 | getName(): string; 9 | execute(); 10 | } 11 | 12 | class Service1 implements Service { 13 | execute(){ 14 | console.log("Executing Service1"); 15 | } 16 | 17 | getName() { 18 | return "Service1"; 19 | } 20 | } 21 | 22 | class Service2 implements Service { 23 | execute(){ 24 | console.log("Executing Service2"); 25 | } 26 | 27 | getName() { 28 | return "Service2"; 29 | } 30 | } 31 | 32 | class InitialContext { 33 | lookup(jndiName: string){ 34 | if(jndiName.toLocaleUpperCase() == ("SERVICE1")){ 35 | console.log("Looking up and creating a new Service1 object"); 36 | return new Service1(); 37 | }else if (jndiName.toLocaleUpperCase() == ("SERVICE2")){ 38 | console.log("Looking up and creating a new Service2 object"); 39 | return new Service2(); 40 | } 41 | return null; 42 | } 43 | } 44 | 45 | class Cache { 46 | 47 | private services: Array ; 48 | 49 | constructor(){ 50 | this.services = new Array(); 51 | } 52 | 53 | public getService(serviceName: string): Service{ 54 | for (let service of this.services) { 55 | if(service.getName().toLocaleUpperCase() == (serviceName.toLocaleUpperCase())){ 56 | console.log("Returning cached "+serviceName+" object"); 57 | return service; 58 | } 59 | } 60 | return null; 61 | } 62 | 63 | addService(newService: Service){ 64 | let exists = false; 65 | for (let service of this.services) { 66 | if(service.getName().toLocaleUpperCase() == (newService.getName().toLocaleUpperCase())){ 67 | exists = true; 68 | } 69 | } 70 | if(!exists){ 71 | this.services.push(newService); 72 | } 73 | } 74 | } 75 | 76 | class ServiceLocator { 77 | private static cache = new Cache(); 78 | 79 | public static getService(jndiName : string) : Service{ 80 | 81 | let service = ServiceLocator.cache.getService(jndiName); 82 | 83 | if(service != null){ 84 | return service; 85 | } 86 | 87 | let context = new InitialContext(); 88 | let service1 : Service = context.lookup(jndiName); 89 | ServiceLocator.cache.addService(service1); 90 | return service1; 91 | } 92 | } 93 | 94 | let service = ServiceLocator.getService("Service1"); 95 | service.execute(); 96 | service = ServiceLocator.getService("Service2"); 97 | service.execute(); 98 | service = ServiceLocator.getService("Service1"); 99 | service.execute(); 100 | service = ServiceLocator.getService("Service2"); 101 | service.execute(); -------------------------------------------------------------------------------- /src/Singleton.ts: -------------------------------------------------------------------------------- 1 | // 饿汉模式 2 | class Singleton1{ 3 | private static _instance = new Singleton1(); 4 | private constructor(){}; 5 | 6 | static getInstance(){ 7 | return Singleton1._instance; 8 | } 9 | } 10 | 11 | 12 | // 懒汉模式 13 | class Singleton2{ 14 | private static _instance : Singleton2; 15 | private constructor(){}; 16 | static getInstance(): Singleton2{ 17 | if(this._instance){ 18 | return this._instance; 19 | } 20 | this._instance = new Singleton2(); 21 | return this._instance; 22 | } 23 | } 24 | 25 | 26 | // 使用闭包的形势构造私有变量 27 | let s3 = (() => { 28 | let _instance; 29 | return (instance = null) => { 30 | if(_instance) return _instance; 31 | if(instance) _instance = instance; 32 | return _instance; 33 | } 34 | })(); 35 | 36 | // 懒汉模式 37 | class Singleton3{ 38 | private constructor(){}; 39 | 40 | static getInstance(){ 41 | if(!s3()){ 42 | return s3(new Singleton3()) 43 | } 44 | return s3(); 45 | } 46 | } 47 | 48 | export { Singleton1, Singleton2 , Singleton3 }; 49 | -------------------------------------------------------------------------------- /src/State.ts: -------------------------------------------------------------------------------- 1 | interface State { 2 | doAction(context: Context); 3 | } 4 | 5 | class StartState implements State { 6 | 7 | doAction(context: Context) { 8 | console.log("Player is in start state"); 9 | context.setState(this); 10 | } 11 | 12 | toString(){ 13 | return "Start State"; 14 | } 15 | } 16 | 17 | class StopState implements State { 18 | 19 | doAction(context: Context) { 20 | console.log("Player is in stop state"); 21 | context.setState(this); 22 | } 23 | 24 | toString(){ 25 | return "Stop State"; 26 | } 27 | } 28 | 29 | class Context { 30 | private state: State; 31 | 32 | constructor(){ 33 | this.state = null; 34 | } 35 | 36 | setState(state: State){ 37 | this.state = state; 38 | } 39 | 40 | getState(): State{ 41 | return this.state; 42 | } 43 | } 44 | 45 | let context = new Context(); 46 | 47 | let startState = new StartState(); 48 | startState.doAction(context); 49 | 50 | console.log(context.getState().toString()); 51 | 52 | let stopState = new StopState(); 53 | stopState.doAction(context); 54 | 55 | console.log(context.getState().toString()); -------------------------------------------------------------------------------- /src/Strategy.ts: -------------------------------------------------------------------------------- 1 | namespace Strategy{ 2 | interface Strategy { 3 | doOperation(num1: number,num2: number) : number; 4 | } 5 | 6 | class OperationAdd implements Strategy{ 7 | doOperation(num1: number, num2: number) { 8 | return num1 + num2; 9 | } 10 | } 11 | 12 | class OperationSubstract implements Strategy{ 13 | doOperation(num1: number, num2: number) { 14 | return num1 - num2; 15 | } 16 | } 17 | 18 | class OperationMultiply implements Strategy{ 19 | doOperation(num1: number, num2: number) { 20 | return num1 * num2; 21 | } 22 | } 23 | 24 | class Context { 25 | private strategy: Strategy; 26 | 27 | constructor(strategy: Strategy){ 28 | this.strategy = strategy; 29 | } 30 | 31 | executeStrategy(num1: number,num2: number): number{ 32 | return this.strategy.doOperation(num1, num2); 33 | } 34 | } 35 | 36 | 37 | let context = new Context(new OperationAdd()); 38 | console.log("10 + 5 = " + context.executeStrategy(10, 5)); 39 | 40 | context = new Context(new OperationSubstract()); 41 | console.log("10 - 5 = " + context.executeStrategy(10, 5)); 42 | 43 | context = new Context(new OperationMultiply()); 44 | console.log("10 * 5 = " + context.executeStrategy(10, 5)); 45 | } 46 | -------------------------------------------------------------------------------- /src/Template.ts: -------------------------------------------------------------------------------- 1 | abstract class Game { 2 | abstract initialize(); 3 | abstract startPlay(); 4 | abstract endPlay(); 5 | //模板 6 | play(){ 7 | //初始化游戏 8 | this.initialize(); 9 | 10 | //开始游戏 11 | this.startPlay(); 12 | 13 | //结束游戏 14 | this.endPlay(); 15 | } 16 | } 17 | 18 | class Cricket extends Game { 19 | 20 | endPlay() { 21 | console.log("Cricket Game Finished!"); 22 | } 23 | 24 | initialize() { 25 | console.log("Cricket Game Initialized! Start playing."); 26 | } 27 | 28 | startPlay() { 29 | console.log("Cricket Game Started. Enjoy the game!"); 30 | } 31 | } 32 | 33 | 34 | class Football extends Game { 35 | 36 | endPlay() { 37 | console.log("Football Game Finished!"); 38 | } 39 | 40 | initialize() { 41 | console.log("Football Game Initialized! Start playing."); 42 | } 43 | 44 | startPlay() { 45 | console.log("Football Game Started. Enjoy the game!"); 46 | } 47 | } 48 | 49 | let game = new Cricket(); 50 | game.play(); 51 | console.log("========\n"); 52 | game = new Football(); 53 | game.play(); 54 | 55 | -------------------------------------------------------------------------------- /src/TransferObject.ts: -------------------------------------------------------------------------------- 1 | // 业务对象(Business Object) - 为传输对象填充数据的业务服务。 2 | // 传输对象(Transfer Object) - 简单的 POJO,只有设置/获取属性的方法。 3 | // 客户端(Client) - 客户端可以发送请求或者发送传输对象到业务对象 4 | 5 | 6 | class StudentVO { 7 | private name: string; 8 | private rollNo: number; 9 | 10 | constructor(name: string, rollNo: number){ 11 | this.name = name; 12 | this.rollNo = rollNo; 13 | } 14 | 15 | getName() { 16 | return this.name; 17 | } 18 | 19 | setName(name: string) { 20 | this.name = name; 21 | } 22 | 23 | getRollNo(): number { 24 | return this.rollNo; 25 | } 26 | 27 | setRollNo(rollNo: number) { 28 | this.rollNo = rollNo; 29 | } 30 | } 31 | 32 | class StudentBO { 33 | 34 | //列表是当作一个数据库 35 | students: Array; 36 | 37 | constructor(){ 38 | let students = new Array(); 39 | let student1 = new StudentVO("Robert",0); 40 | let student2 = new StudentVO("John",1); 41 | students.push(student1); 42 | students.push(student2); 43 | } 44 | deleteStudent(student: StudentVO) { 45 | this.students.splice(student.getRollNo(), 1); 46 | console.log("Student: Roll No " 47 | + student.getRollNo() +", deleted from database"); 48 | } 49 | 50 | //从数据库中检索学生名单 51 | getAllStudents(): Array { 52 | return this.students; 53 | } 54 | 55 | getStudent(rollNo: number) { 56 | return this.students[rollNo]; 57 | } 58 | 59 | updateStudent(student: StudentVO) { 60 | this.students[student.getRollNo()].setName(student.getName()); 61 | console.log("Student: Roll No " 62 | + student.getRollNo() +", updated in the database"); 63 | } 64 | } 65 | 66 | 67 | let studentBusinessObject = new StudentBO(); 68 | 69 | //输出所有的学生 70 | for (let student of studentBusinessObject.getAllStudents()) { 71 | console.log("Student: [RollNo : " 72 | +student.getRollNo()+", Name : "+student.getName()+" ]"); 73 | } 74 | 75 | //更新学生 76 | let student =studentBusinessObject.getAllStudents().get(0); 77 | student.setName("Michael"); 78 | studentBusinessObject.updateStudent(student); 79 | 80 | //获取学生 81 | studentBusinessObject.getStudent(0); 82 | console.log("Student: [RollNo : " 83 | +student.getRollNo()+", Name : "+student.getName()+" ]"); -------------------------------------------------------------------------------- /src/Visitor.ts: -------------------------------------------------------------------------------- 1 | interface ComputerPart { 2 | accept(computerPartVisitor: ComputerPartVisitor); 3 | } 4 | 5 | class Keyboard implements ComputerPart { 6 | 7 | accept(computerPartVisitor: ComputerPartVisitor) { 8 | computerPartVisitor.visit(this); 9 | } 10 | 11 | } 12 | 13 | class Monitor implements ComputerPart { 14 | accept(computerPartVisitor: ComputerPartVisitor) { 15 | computerPartVisitor.visit(this); 16 | } 17 | } 18 | 19 | class Mouse implements ComputerPart { 20 | 21 | accept(computerPartVisitor: ComputerPartVisitor) { 22 | computerPartVisitor.visit(this); 23 | } 24 | } 25 | 26 | class Computer implements ComputerPart { 27 | 28 | parts: ComputerPart[] ; 29 | 30 | constructor(){ 31 | this.parts = [new Mouse(), new Keyboard(), new Monitor()]; 32 | } 33 | 34 | 35 | accept(computerPartVisitor: ComputerPartVisitor) { 36 | for (let i = 0; i < this.parts.length; i++) { 37 | this.parts[i].accept(computerPartVisitor); 38 | } 39 | computerPartVisitor.visit(this); 40 | } 41 | } 42 | 43 | interface ComputerPartVisitor { 44 | visit(computer: Computer); 45 | visit(mouse: Mouse); 46 | visit(keyboard: Keyboard); 47 | visit(monitor: Monitor); 48 | } 49 | 50 | class ComputerPartDisplayVisitor implements ComputerPartVisitor { 51 | visit(computer: Computer); 52 | visit(mouse: Mouse); 53 | visit(keyboard: Keyboard); 54 | visit(monitor: Monitor); 55 | visit(obj: Computer | Mouse | Keyboard | Monitor) { 56 | if(obj instanceof Computer) { 57 | console.log("Displaying Computer."); 58 | }else if(obj instanceof Mouse){ 59 | console.log("Displaying Mouse."); 60 | }else if(obj instanceof Keyboard){ 61 | console.log("Displaying Keyboard."); 62 | }else if(obj instanceof Monitor){ 63 | console.log("Displaying Monitor."); 64 | } 65 | } 66 | 67 | // typescript 貌似并不能支持类方法多次声明, 只能实现一次 68 | 69 | // visit(mouse: Mouse) { 70 | // console.log("Displaying Mouse."); 71 | // } 72 | 73 | // visit(keyboard: Keyboard) { 74 | // console.log("Displaying Keyboard."); 75 | // } 76 | 77 | // visit(monitor: Monitor) { 78 | // console.log("Displaying Monitor."); 79 | // } 80 | } 81 | 82 | let computer = new Computer(); 83 | computer.accept(new ComputerPartDisplayVisitor()); 84 | 85 | -------------------------------------------------------------------------------- /test/Builder.test.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | import { Meal, MealBuilder, ChickenBurger, VegBurger, Coke, Pepsi } from '../src/Builder'; 4 | 5 | test('MealBuilder get a Meal', (t) => { 6 | let mlb = new MealBuilder(); 7 | let m1 = mlb.prepareVegMeal(); 8 | let m2 = mlb.prepareNotVegMeal(); 9 | t.true(m1 instanceof Meal); 10 | t.true(m2 instanceof Meal); 11 | 12 | t.is(m1.getCost(), (new VegBurger().price())+(new Coke().price())); 13 | t.is(m2.getCost(), (new ChickenBurger().price())+(new Pepsi().price())) 14 | }); -------------------------------------------------------------------------------- /test/Factory.test.ts: -------------------------------------------------------------------------------- 1 | import ava from 'ava'; 2 | import { Mother, Jelly, XiaoMi, AllFactory, fieldTest, Battery } from '../src/Factory'; 3 | 4 | 5 | ava('test Mother', (t)=>{ 6 | // 宝宝要开始提需求了 7 | // 宝宝要糖糖 8 | let jelly = Mother.giveMe('tangtang'); 9 | 10 | // 宝宝要飞飞 11 | let toyPlane = Mother.giveMe('feifei'); 12 | 13 | t.true(jelly instanceof Jelly ); // 妈妈给宝宝果冻 14 | t.true(jelly.chewed); // 宝宝得到的果冻是经过处理的 15 | t.true(toyPlane === null) // 妈妈不同意买飞机 16 | }) 17 | 18 | 19 | ava('test XiaoMi Factory', (t)=>{ 20 | t.true(XiaoMi('battery').getBattery() instanceof Battery); 21 | t.true(XiaoMi('screen').getScreen().name === 'screen'); 22 | 23 | }) 24 | 25 | 26 | let email = 'belovedyogurt@gmail.com'; 27 | let myname = "陈大明"; 28 | 29 | ava('fieldTest' , t => { 30 | t.true(fieldTest('email').test(email)); 31 | t.true(fieldTest('character').test(myname)); 32 | }) 33 | 34 | 35 | ava('AllFactory', t => { 36 | let mom = AllFactory.getMother(); 37 | 38 | let test = AllFactory.getFieldTest(); 39 | 40 | t.true(mom === Mother); 41 | t.true(test('email').test(email)); 42 | }) 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /test/Singleton.test.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | import { Singleton1, Singleton2, Singleton3 } from '../src/Singleton'; 4 | 5 | test("test Singleton1",(t) => { 6 | let instance1 = Singleton1.getInstance(); 7 | let instance2 = Singleton1.getInstance(); 8 | t.is(instance1 instanceof Singleton1, true); 9 | t.is(instance1 === instance2, true); 10 | }); 11 | 12 | test("test Singleton2",(t) => { 13 | let instance1 = Singleton2.getInstance(); 14 | let instance2 = Singleton2.getInstance(); 15 | t.is(instance1 instanceof Singleton2, true); 16 | t.is(instance1 === instance2, true); 17 | }); 18 | 19 | test("test Singleton3",(t) => { 20 | let instance1 = Singleton3.getInstance(); 21 | let instance2 = Singleton3.getInstance(); 22 | t.is(instance1 instanceof Singleton3, true); 23 | t.is(instance1 === instance2, true); 24 | }); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2015", 5 | "noImplicitAny": false, 6 | "sourceMap": true 7 | } 8 | } --------------------------------------------------------------------------------