做者簡介 joey 螞蟻金服·數據體驗技術團隊html
繼前文Typescript玩轉設計模式 之 結構型模式(上)以後,本週帶來的是系列文章之三,講解的是4種結構性模式:java
結構性模式分爲7種,本文先講解其中四種,剩餘3種下一篇文章再進行討論~git
將一個類的接口轉換成客戶但願的另一個接口。Adapter模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做。github
適配器模式由如下角色構成:編程
電源插座是220V的,但手機充電時只須要5V,所以咱們須要一個適配器讓手機能在220V插座上充電。設計模式
// 適配器有2種實現模式,類模式和對象模式
// 目標接口
interface Voltage5vInterface {
connect5v(): void;
}
// 被適配類
class Voltage220v {
connect220v() {
console.log('接通220V電源,');
}
}
// 客戶類,保存對適配器對象的引用關係,經過訪問適配器對象來間接使用被適配對象
// 這裏,手機充電時只須要知道適配器對象的5V接口就能調用被適配的220V插座來充電了
class Phone {
private voltage5v: Voltage5vInterface;
constructor(voltage5v: Voltage5vInterface) {
this.voltage5v = voltage5v;
}
charge(): void {
this.voltage5v.connect5v();
console.log('已經接通電源,手機開始充電');
}
}
// 類適配器
// Voltage220v是被適配的類,接口跟最終要求不一致
// Voltage5vInterface包含想要提供的接口
// 所以"繼承"被適配的類,"實現"想要支持的接口
class ClassPowerAdapter extends Voltage220v implements Voltage5vInterface {
connect5v(): void {
this.connect220v();
console.log('將220V電源轉化爲5v電源,');
}
}
function classAdapterDemo() {
const adapter = new ClassPowerAdapter();
const phone = new Phone(adapter);
phone.charge();
}
classAdapterDemo();
// 對象適配器
// 適配器中持有被適配類的對象的引用
class InstancePowerAdapter implements Voltage5vInterface {
private voltage220v: Voltage220v;
constructor(voltage220v: Voltage220v) {
this.voltage220v = voltage220v;
}
connect5v(): void {
this.voltage220v.connect220v();
console.log('將220V電源轉化爲5v電源,');
}
}
function instanceAdapterDemo() {
const voltage220v = new Voltage220v();
const adapter = new InstancePowerAdapter(voltage220v);
const phone = new Phone(adapter);
phone.charge();
}
instanceAdapterDemo();
複製代碼
同一個接口適配不一樣的類bash
電腦有個USB接口,能夠插入華爲手機或iphone的數據線iphone
// 電腦的USB接口
interface ComputerInterface {
usb(): void;
}
// 華爲手機,有本身的數據接口
class HuaweiPhone {
huaweiInterface(): void {
console.log('華爲手機的數據接口');
}
}
// iphone,有本身的數據接口
class Iphone {
iphoneInterface(): void {
console.log('蘋果手機的數據接口');
}
}
// 華爲手機數據線適配器
class HuaweiDataWireAdapter extends HuaweiPhone implements ComputerInterface {
usb(): void {
console.log('使用華爲數據線鏈接');
super.huaweiInterface();
}
}
// iphone手機數據線適配器
class IphoneDataWireAdapter extends Iphone implements ComputerInterface {
usb(): void {
console.log('使用蘋果數據線鏈接');
super.iphoneInterface();
}
}
function commonAdapterDemo() {
const computer1 = new HuaweiDataWireAdapter();
computer1.usb();
const computer2 = new IphoneDataWireAdapter();
computer2.usb();
}
commonAdapterDemo();
複製代碼
將抽象部分與他的實現部分分離,使他們均可以獨立地變化。post
橋接模式包含如下角色:this
// 汽車是一個維度,有多種不一樣的車型
abstract class AbstractCar {
abstract run(): void;
}
// 路是一個維度,有多種不一樣的路
abstract class AbstractRoad {
car: AbstractCar;
abstract snapshot(): void;
}
/**
* 汽車和路兩個維度
* 橋接就是一個維度的類中引用了另外一個維度的對象,但只關心接口不關心是哪一個具體的類
* 從而實現兩個維度獨立變化
*/
class SpeedRoad extends AbstractRoad {
constructor(car: AbstractCar) {
super();
this.car = car;
}
snapshot(): void {
console.log('在高速公路上');
this.car.run();
}
}
class Street extends AbstractRoad {
constructor(car: AbstractCar) {
super();
this.car = car;
}
snapshot(): void {
console.log('在市區街道上');
this.car.run();
}
}
class Car extends AbstractCar {
run(): void {
console.log('開着小汽車');
}
}
class Bus extends AbstractCar {
run(): void {
console.log('開着公共汽車');
}
}
function carRunOnRoadDemo(): void {
// 在高速公路上,開着小汽車
const car = new Car();
const speedRoad = new SpeedRoad(car);
speedRoad.snapshot();
// 在市區街道上,開着公共汽車
const bus = new Bus();
const street = new Street(bus);
street.snapshot();
}
carRunOnRoadDemo();
/**
* 人,汽車和路三個維度
*/
abstract class Person {
road: AbstractRoad;
abstract see(): void;
}
class Man extends Person {
constructor(road: AbstractRoad) {
super();
this.road = road;
}
see(): void {
console.log('男人看到');
this.road.snapshot();
}
}
class Woman extends Person {
constructor(road: AbstractRoad) {
super();
this.road = road;
}
see(): void {
console.log('女人看到');
this.road.snapshot();
}
}
function personSeeCarOnRoadDemo() {
// 男人看到 在市區街道上 開着小汽車
const car = new Car();
const street = new Street(car);
const man = new Man(street);
man.see();
}
personSeeCarOnRoadDemo();
複製代碼
將對象組合成樹形結構以表示「部分-總體」的層次結構。Composite使得用戶對單個對象和組合對象的使用具備一致性。
組合模式包含如下角色:
// 抽象類 人,提供戰鬥接口
abstract class Human {
name: string;
constructor(name: string) {
this.name = name;
}
abstract fight(): void;
}
// 士兵類,戰鬥操做是本身加入戰鬥
class Soldier extends Human {
fight() {
console.log(`${this.name} 準備加入戰鬥`);
}
}
// 指揮官類,戰鬥操做是遞歸召集本身的下屬,集合部隊
class Commander extends Human {
soldiers: Set<Soldier>;
constructor(name: string) {
super(name);
this.soldiers = new Set<Soldier>();
}
add(soldier: Soldier) {
this.soldiers.add(soldier);
}
remove(soldier: Soldier) {
this.soldiers.delete(soldier);
}
fight() {
console.log(`${this.name} 開始召集屬下`);
this.soldiers.forEach(soldier => soldier.fight());
console.log(`${this.name} 部隊集結完畢`);
}
}
// 在使用組合模式時,全部對象都有'fight'方法,所以不須要關心對象是士兵仍是指揮官,即不須要關心是單個對象仍是組合對象
function battleDemo() {
const soldier1 = new Soldier('soldier1');
const soldier2 = new Soldier('soldier2');
const soldier3 = new Soldier('soldier3');
const soldier4 = new Soldier('soldier4');
const subCommander1 = new Commander('subCommander1');
subCommander1.add(soldier1);
subCommander1.add(soldier2);
const subCommander2 = new Commander('subCommander2');
subCommander2.add(soldier3);
subCommander2.add(soldier4);
const chiefCommander = new Commander('chiefCommander');
chiefCommander.add(subCommander1);
chiefCommander.add(subCommander2);
chiefCommander.fight();
}
battleDemo();
複製代碼
動態地給一個對象添加一些額外的職責。就增長功能來講,Decorator模式相比生成子類更爲靈活。
裝飾模式包含如下角色:
// 抽象構件——可視化組件
class VisualComponent {
draw(): void {
console.log('繪製一個組件');
}
}
// 裝飾器基類,裝飾可視化組件
class Decorator extends VisualComponent {
protected component: VisualComponent;
constructor(component: VisualComponent) {
super();
this.component = component;
}
draw(): void {
this.component.draw();
}
}
// 帶邊框的裝飾器
class BorderDecorator extends Decorator {
protected width: number;
constructor(component: VisualComponent, borderWidth: number) {
super(component);
this.width = borderWidth;
}
private drawBorder(): void {
console.log(`繪製寬度爲${this.width}的邊框`);
}
draw() {
this.drawBorder();
this.component.draw();
}
}
// 帶滾動條的裝飾器
class ScrollDecorator extends Decorator {
private drawScrollBar(): void {
console.log('繪製滾動欄');
}
draw(): void {
this.drawScrollBar();
this.component.draw();
}
}
// 繪製一個帶滾動條和邊框的組件
function decoratorDemo() {
const component = new VisualComponent();
const finalComponent = new BorderDecorator(new ScrollDecorator(component), 1);
finalComponent.draw();
}
decoratorDemo();
複製代碼
typeof
不能指向Component類本文介紹了前4種結構型模式,對後續模式感興趣的同窗能夠關注專欄或者發送簡歷至'chaofeng.lcf####alibaba-inc.com'.replace('####', '@'),歡迎有志之士加入~