前端工程中的设计模式应用(中)

简介: 前端工程中的设计模式应用(中)

更多精彩内容,欢迎观看:

前端工程中的设计模式应用(上):https://developer.aliyun.com/article/1396344


 结构型


结构型模式介绍如何将对象和类组装成较大的结构, 并同时保持结构的灵活和高效。


  • 桥接模式


桥接模式是一种结构型设计模式, 可将一个大类或一系列紧密相关的类拆分为不同的层次结构, 从而能在开发时分别使用。


桥接模式结构:


代码实现:

// 定义了所有Implementation类的接口
interface Implementation {
    operationImplementation(): string;
}
class Abstraction {// 提供对Implementation的引用,并将所有的实际工作委托给它
    protected implementation: Implementation;
    constructor(implementation: Implementation) {
        this.implementation = implementation;
    }
    public operation(): string {
        const result = this.implementation.operationImplementation();
        return `抽象部分: 基础操作: ${result}`;
    }
}
// 在不改变Implementation类的前提下继承Abstraction
class ExtendedAbstraction extends Abstraction {
    public operation(): string {
        const result = this.implementation.operationImplementation();
        return `继承的抽象部分: 继承的操作:${result}`;
    }
}
class ConcreteImplementationA implements Implementation {
    public operationImplementation(): string {
        return '具体实现A: 这里是A的结果';
    }
}
class ConcreteImplementationB implements Implementation {
    public operationImplementation(): string {
        return '具体实现B: 这里是B的结果';
    }
}
// 客户端代码
function clientCode(abstraction: Abstraction) {
    console.log(abstraction.operation());
}
let implementation = new ConcreteImplementationA();
let abstraction = new Abstraction(implementation);
clientCode(abstraction); // 抽象部分:基础操作:具体实现A: 这里是A的结果.
implementation = new ConcreteImplementationB();
abstraction = new ExtendedAbstraction(implementation);
clientCode(abstraction); // 继承的抽象部分: 继承的操作: 具体实现B: 这里是B的结果.

简单来说,对于一个复杂庞大的系统,可以将其分层,第一层是抽象层,第二层为具体层,抽象层可以把对自己的调用委派给实现层实现,而所有的实现层都具有统一接口,所以实现层可以在抽象部分内部进行相互替换。

  • 外观模式


外观模式是一种结构型设计模式, 能为程序库、 框架或其他复杂类提供一个简单的接口。

举个现实的例子,淘宝就是一个外观,它提供了你购物、支付、送花上门等接口。
外观模式结构:
代码实现:

// 为一个或多个子系统的复杂逻辑提供简单接口
class Facade {
    protected subsystem1: Subsystem1;
    protected subsystem2: Subsystem2;
    constructor(subsystem1?: Subsystem1, subsystem2?: Subsystem2) {
        this.subsystem1 = subsystem1 || new Subsystem1();
        this.subsystem2 = subsystem2 || new Subsystem2();
    }
    public operation(): string {
        let result = 'Facade初始化子系统';
        result += this.subsystem1.operation1();
        result += this.subsystem2.operation1();
        result += 'Facade命令子系统执行操作';
        result += this.subsystem1.operationN();
        result += this.subsystem2.operationZ();
        return result;
    }
}
class Subsystem1 {
    public operation1(): string {
        return 'Subsystem1准备好了!';
    }
    public operationN(): string {
        return 'Subsystem1执行!';
    }
}
class Subsystem2 {
    public operation1(): string {
        return 'Subsystem2准备好了';
    }
    public operationZ(): string {
        return 'Subsystem2执行!';
    }
}
// 客户端代码
function clientCode(facade: Facade) {
    console.log(facade.operation());
}
const subsystem1 = new Subsystem1();
const subsystem2 = new Subsystem2();
const facade = new Facade(subsystem1, subsystem2);
clientCode(facade); // Facade初始化子系统 Subsystem1准备好了! Subsystem2准备好了 Facade命令子系统执行操作 Subsystem1执行! Subsystem2执行!
  • 组合模式


组合模式是一种结构型设计模式, 你可以使用它将对象组合成树状结构, 并且能像使用独立对象一样使用它们。


举个现实的例子,比如学校,学校由年级组成,年级由班级组成,班级由学生个体组成。当学校下达重要通知时,是逐级下发的,通过一个个层级的传递,直到每个学生都接收到通知。


组合模式结构:


代码示例:

// 描述了 简单 和 复杂 所共有的操作
abstract class Component {
    protected parent!: Component | null;
    public setParent(parent: Component | null) {
        this.parent = parent;
    }
    public getParent(): Component | null {
        return this.parent;
    }
    public add(component: Component): void { }
    public remove(component: Component): void { }
    public isComposite(): boolean {
        return false;
    }
    public abstract operation(): string;
}
// 叶子 执行具体的工作,不再包含子项目
class Leaf extends Component {
    public operation(): string {
        return 'Leaf';
    }
}
// 容器 将具体工作委托给子项目,然后汇总结果
class Composite extends Component {
    protected children: Component[] = [];
    public add(component: Component): void {
        this.children.push(component);
        component.setParent(this);
    }
    public remove(component: Component): void {
        const componentIndex = this.children.indexOf(component);
        this.children.splice(componentIndex, 1);
        component.setParent(null);
    }
    public isComposite(): boolean {
        return true;
    }
    public operation(): string {
        const results = [];
        for (const child of this.children) {
            results.push(child.operation());
        }
        return `Branch(${results.join('+')})`;
    }
}
// 客户端 通过基础接口与所有的组件链接
function clientCode(component: Component) {
    console.log(`RESULT: ${component.operation()}`);
}
const simple = new Leaf();
console.log('Client: 简单的:');
clientCode(simple); // RESULT: Leaf
const tree = new Composite();
const branch1 = new Composite();
branch1.add(new Leaf());
branch1.add(new Leaf());
const branch2 = new Composite();
branch2.add(new Leaf());
tree.add(branch1);
tree.add(branch2);
console.log('Client: 复杂的:');
clientCode(tree); // RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf))
function clientCode2(component1: Component, component2: Component) {
    if (component1.isComposite()) {
        component1.add(component2);
    }
    console.log(`RESULT: ${component1.operation()}`);
}
console.log('Client: 当在管理树状结构时,不需要检查组件类');
clientCode2(tree, simple); // RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf)+Leaf)

简单来说,组合模式最主要的功能是在整个树状结构上递归调用方法并对结果进行汇总。


  • 装饰器模式


装饰模式是一种结构型设计模式, 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。

举个现实的例子,比如天冷加衣服,觉得冷了可以加一件毛衣,还觉得冷可以再加一件羽绒服。这些衣物扩展了你的基本行为,但他们并不是你的一部分,如果不再需要了,可以随时脱掉。如果下雨了,还可以随时再加一件雨衣。
装饰器模式结构:
代码示例:

interface Component { // 定义了可被装饰器修改的操作
    operation(): string;
}
// 具体部件提供了操作的默认实现 但是装饰类可以改变这些操作
class ConcreteComponent implements Component {
    public operation(): string {
        return 'ConcreteComponent';
    }
}
// 
class Decorator implements Component {
    protected component: Component;
    constructor(component: Component) {
        this.component = component;
    }
    public operation(): string {
        return this.component.operation();
    }
}
class ConcreteDecoratorA extends Decorator {
    public operation(): string {
        return `ConcreteDecoratorA(${super.operation()})`;
    }
}
class ConcreteDecoratorB extends Decorator {
    public operation(): string {
        return `ConcreteDecoratorB(${super.operation()})`;
    }
}
// 客户端
function clientCode(component: Component) {
    console.log(`RESULT: ${component.operation()}`);
}
const simple = new ConcreteComponent();
console.log('Client: 简单的部件:');
clientCode(simple); // RESULT: ConcreteComponent
const decorator1 = new ConcreteDecoratorA(simple);
const decorator2 = new ConcreteDecoratorB(decorator1);
console.log('Client: 装饰器部件:');
clientCode(decorator2); // RESULT: ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))

简答来说,目标对象和装饰器是遵循同一接口的,因此可以使用装饰对对象进行无限次的封装,结果对象将获得所有装饰器装饰后的叠加结果。

  • 适配器模式


适配器模式是一种结构型设计模式, 它能使接口不兼容的对象能够相互合作。

举个现实的例子,电源适配器。
适配器模式结构:

代码示例:

class Target { // 目标
    public request(): string {
        return 'Target: The default target\'s behavior.';
    }
}
class Adaptee { // 被适配者
    public specificRequest(): string {
        return '.eetpadA eht fo roivaheb laicepS';
    }
}
class Adapter extends Target {
    private adaptee: Adaptee;
    constructor(adaptee: Adaptee) {
        super();
        this.adaptee = adaptee;
    }
    public request(): string {
        const result = this.adaptee.specificRequest().split('').reverse().join('');
        return `Adapter: (TRANSLATED) ${result}`;
    }
} 
// 客户端 支持所有遵循Target接口的类
function clientCode(target: Target) {
    console.log(target.request());
}
const target = new Target();
clientCode(target); // Target: 这是默认的目标行为.
const adaptee = new Adaptee();
console.log(`Adaptee: ${adaptee.specificRequest()}`); // Adaptee: .eetpadA eht fo roivaheb laicepS
const adapter = new Adapter(adaptee);
clientCode(adapter); // Adapter: (TRANSLATED) Special behavior of the Adaptee.

简而言之,适配器接收对一个对象的调用,并将其转换为另一个对象可识别的格式和接口。


  • 代理模式


代理模式是一种结构型设计模式, 它能够提供对象的替代品或占位符。代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。


举个现实的例子,我们的数字支付工具比如支付宝支付、微信支付就是现金的代理,他们都实现了同一的接口,均可以用于支付。消费者和被消费者都会非常的满意,因为双方都很便捷。


代理模式结构:


代码示例:

interface ServiceInterface { // 声明服务接口,实际服务者和代理者要遵循相同的接口
    request(): void;
}
// 实际服务者
class Service implements ServiceInterface {
    public request(): void {
        console.log('实际服务者: 处理请求');
    }
}
// 代理者
class Proxy implements ServiceInterface {
    private service: Service;
    // 代理会维护一个对实际服务者的引用
    constructor(service: Service) {
        this.service = service;
    }
    public request(): void {
        if (this.checkAccess()) {
            this.service.request();
            this.logAccess();
        }
    }
    private checkAccess(): boolean {
        // 在这里执行一些处理
        console.log('代理:触发真正的请求之前进行检查访问');
        return true;
    }
    private logAccess(): void {
        console.log('代理:请求之后的一些处理');
    }
}
// 客户端代码
function clientCode(serviceInterface: ServiceInterface) {
    serviceInterface.request();
}
// 客户端直接调用实际服务者
const service = new Service(); 
clientCode(service); // 实际服务者: 处理请求.
// 客户端通过代理调用实际服务者
const proxy = new Proxy(service);
clientCode(proxy); // 代理:触发真正的请求之前进行检查访问. 实际服务者: 处理请求. 代理:请求之后的一些处理
  • 享元模式


享元模式是一种结构型设计模式, 它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在有限的内存容量中载入更多对象。
享受元模式结构:


代码示例:

// 存储共有状态,接收其余状态
class Flyweight {
  private sharedState: any;
  constructor(sharedState: any) {
    this.sharedState = sharedState;
  }
  public operation(uniqueState): void {
    const s = JSON.stringify(this.sharedState);
    const u = JSON.stringify(uniqueState);
    console.log(`享元: 共享 (${s}),独有 (${u})`);
  }
}
// 创建和管理Flyweight对象
class FlyweightFactory {
  private flyweights: {[key: string]: Flyweight} = <any>{};
  constructor(initialFlyweights: string[][]) {
    for (const state of initialFlyweights) {
      this.flyweights[this.getKey(state)] = new Flyweight(state);
    }
  }
  private getKey(state: string[]): string {
    return state.join('_');
  }
  public getFlyweight(sharedState: string[]): Flyweight {
    const key = this.getKey(sharedState);
    if (!(key in this.flyweights)) {
      console.log('享元工厂: 不能够寻找到享元,创建一个新的');
      this.flyweights[key] = new Flyweight(sharedState);
    } else {
      console.log('享元工厂: 找到了已存在的享元');
    }
    return this.flyweights[key];
  }
  public listFlyweights(): void {
    const count = Object.keys(this.flyweights).length;
    console.log(`享元工厂: 我有 ${count} 个享元:`);
    for (const key in this.flyweights) {
      console.log(key);
    }
  }
}
// 客户端代码  先创建一些预先填充的flyweight
const factory = new FlyweightFactory([
  ['Chevrolet', 'Camaro2018', 'pink'],
  ['Mercedes Benz', 'C300', 'black'],
  ['Mercedes Benz', 'C500', 'red'],
  ['BMW', 'M5', 'red'],
  ['BMW', 'X6', 'white'],
]);
factory.listFlyweights(); // 享元工厂: 我有5个享元:
// Chevrolet-Camaro2018-pink
// Mercedes Benz-C300-black
// Mercedes Benz-C500-red
// BMW-M5-red
// BMW-X6-white
function addCarToPoliceDatabase(
  ff: FlyweightFactory, plates: string, owner: string,
  brand: string, model: string, color: string,
) {
  const flyweight = ff.getFlyweight([brand, model, color]);
  flyweight.operation([plates, owner]);
}
addCarToPoliceDatabase(factory, 'CL234IR', 'James Doe', 'BMW', 'M5', 'red'); 
// 享元工厂: 找到了已存在的享元.
// 享元: 共享 (['BMW', 'M5', 'red']), 独有 (['CL234IR', 'James Doe']).
addCarToPoliceDatabase(factory, 'CL234IR', 'James Doe', 'BMW', 'X1', 'red');
// 享元工厂: 不能够寻找到享元,创建一个新的
// 享元: 共享 (['BMW', 'X1', 'red']), 独有 (['CL234IR', 'James Doe']) state.
factory.listFlyweights(); // 享元工厂: 我有6个享元:
// Chevrolet-Camaro2018-pink
// Mercedes Benz-C300-black
// Mercedes Benz-C500-red
// BMW-M5-red
// BMW-X6-white
// BMW-X1-red

简单来说,享元模式通过共享多个对象的部分状态来实现上述功能,享元会将不同对象的相同数据进行缓存以节省内存。如同上述例子中,车的型号会被存储在享元中,车的主人是独享的。当将一个 主人-车辆 数据加入数据库中时,享元工厂先查找享元中是否已存在该型号车的数据,有的话直接返回,没有的话创建这个型号。

 行为型


行为模式负责对象间的高效沟通和职责委派。


  • 迭代器模式


迭代器模式是一种行为设计模式, 它能够在不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素。


举个现实的例子,假如去北京旅游,故宫、长城、天安门、颐和园、北大、清华是此次旅行的游览目标,可以将他们组成一个目的地集合。第一种游览方式是按照自己的意愿顺序去游玩,第二种方式是按照某些博主推荐的游览顺序游玩,第三种方式是报个旅行团,按照旅行团安排的顺序游玩。以上这三种选择就是目的地集合的迭代器。


迭代器模式结构:


代码示例:

interface Iterator<T> {
    current(): T; // 返回当前的元素
    next(): T; // 返回下一个元素
    key(): number; // 返回当前元素的key
    valid(): boolean; // 检测当前位置是否是有效的
    rewind(): void; // 将迭代器回退到第一个元素
}
interface Aggregator {
    getIterator(): Iterator<string>; // 获取外部迭代器
}
// 具体迭代器实现各种遍历算法。这些类在任何时候都存储当前遍历位置
class AlphabeticalOrderIterator implements Iterator<string> {
    private collection: WordsCollection;
    private position: number = 0;
    private reverse: boolean = false;
    constructor(collection: WordsCollection, reverse: boolean = false) {
        this.collection = collection;
        this.reverse = reverse;
        if (reverse) {
            this.position = collection.getCount() - 1;
        }
    }
    public rewind() {
        this.position = this.reverse ?
            this.collection.getCount() - 1 :
            0;
    }
    public current(): string {
        return this.collection.getItems()[this.position];
    }
    public key(): number {
        return this.position;
    }
    public next(): string {
        const item = this.collection.getItems()[this.position];
        this.position += this.reverse ? -1 : 1;
        return item;
    }
    public valid(): boolean {
        if (this.reverse) {
            return this.position >= 0;
        }
        return this.position < this.collection.getCount();
    }
}
// 具体集合提供一个或多个方法来检索新的迭代器实例,与集合类兼容。
class WordsCollection implements Aggregator {
    private items: string[] = [];
    public getItems(): string[] {
        return this.items;
    }
    public getCount(): number {
        return this.items.length;
    }
    public addItem(item: string): void {
        this.items.push(item);
    }
    public getIterator(): Iterator<string> {
        return new AlphabeticalOrderIterator(this);
    }
    public getReverseIterator(): Iterator<string> {
        return new AlphabeticalOrderIterator(this, true);
    }
}
// 客户端代码
const collection = new WordsCollection();
collection.addItem('First');
collection.addItem('Second');
collection.addItem('Third');
const iterator = collection.getIterator();
console.log('Straight traversal:');
while (iterator.valid()) {
    console.log(iterator.next()); // First Second Third
}
const reverseIterator = collection.getReverseIterator();
while (reverseIterator.valid()) {
    console.log(reverseIterator.next()); // Third Second First
}

最简单的理解方式的话,其实就是我们常说的ES6中的迭代器。


  • 解释器模式


解释器模式是一种行为设计模式。给定一个语言, 定义它的文法的一种表示,并定义一个解释器, 该解释器使用该表示来解释语言中的句子。


代码示例:

class Context {
  constructor() {
    this._list = []; // 存放 终结符表达式
    this._sum = 0; // 存放 非终结符表达式(运算结果)
  }
  get sum() {
    return this._sum;
  }
  set sum(newValue) {
    this._sum = newValue;
  }
  add(expression) {
    this._list.push(expression);
  }
  get list() {
    return [...this._list];
  }
}
class PlusExpression {
  interpret(context) {
    if (!(context instanceof Context)) {
      throw new Error("TypeError");
    }
    context.sum = ++context.sum;
  }
}
class MinusExpression {
  interpret(context) {
    if (!(context instanceof Context)) {
      throw new Error("TypeError");
    }
    context.sum = --context.sum;
  }
}
// 客户端代码
const context = new Context();
// 添加加法表达式
context.add(new PlusExpression()); 
// 添加加法表达式
context.add(new PlusExpression());
// 添加减法表达式
context.add(new MinusExpression());
// 依次执行: 加法、加法、减法表达式
context.list.forEach(expression => expression.interpret(context));
console.log(context.sum); // 1
  • 观察者模式


观察者模式是一种行为设计模式,又被称为发布订阅模式。它允许定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。
举个现实的例子,比如你订阅了人民日报,每当它发版的时候,都会有邮递员将报纸送到你手中,而不需要你跑去报刊亭自己购买。出版社为发布者,你为订阅者,出版社维护着一份订阅者的名单,当你不想再订阅时可以申请退出订阅。
观察者模式结构:


代码示例:

interface Subject { // 声明了一组管理订阅者的方法
    attach(observer: Observer): void; // 为订阅者附加观察者
    detach(observer: Observer): void; // 从订阅者身上剥离观察者
    notify(): void; // 通知所有观察者的方法
}
// 具体订阅者
class ConcreteSubject implements Subject { 
    public state: number;
    private observers: Observer[] = [];
    public attach(observer: Observer): void {
        const isExist = this.observers.includes(observer);
        if (isExist) {
            return console.log('Subject: Observer has been attached already.');
        }
        console.log('Subject: Attached an observer.');
        this.observers.push(observer);
    }
    public detach(observer: Observer): void {
        const observerIndex = this.observers.indexOf(observer);
        if (observerIndex === -1) {
            return console.log('Subject: Nonexistent observer.');
        }
        this.observers.splice(observerIndex, 1);
        console.log('Subject: Detached an observer.');
    }
    // 触发每个订阅者更新
    public notify(): void {
        console.log('Subject: Notifying observers...');
        for (const observer of this.observers) {
            observer.update(this);
        }
    }
    // 业务逻辑等,当其发生变化时,触发notify方法
    public someBusinessLogic(): void {
        console.log('\nSubject: I\'m doing something important.');
        this.state = Math.floor(Math.random() * (10 + 1));
        console.log(`Subject: My state has just changed to: ${this.state}`);
        this.notify();
    }
}
interface Observer { // 声明更新方法,由订阅者调用
    // Receive update from subject.
    update(subject: Subject): void;
}
// 具体观察者
class ConcreteObserverA implements Observer {
    public update(subject: Subject): void {
        if (subject instanceof ConcreteSubject && subject.state < 3) {
            console.log('ConcreteObserverA: Reacted to the event.');
        }
    }
}
class ConcreteObserverB implements Observer {
    public update(subject: Subject): void {
        if (subject instanceof ConcreteSubject && (subject.state === 0 || subject.state >= 2)) {
            console.log('ConcreteObserverB: Reacted to the event.');
        }
    }
}
// 客户端代码
const subject = new ConcreteSubject();
const observer1 = new ConcreteObserverA();
subject.attach(observer1); // Subject: Attached an observer.
const observer2 = new ConcreteObserverB();
subject.attach(observer2); // Subject: Attached an observer.
subject.someBusinessLogic(); // Subject: I'm doing something important. Subject: My state has just changed to: 6.  Subject: Notifying observers...  ConcreteObserverB: Reacted to the event.    
subject.someBusinessLogic(); // Subject: I'm doing something important. Subject: My state has just changed to: 1.  Subject: Notifying observers... ConcreteObserverA: Reacted to the event.  
subject.detach(observer2); // Subject: Detached an observer.
subject.someBusinessLogic(); // Subject: I'm doing something important. Subject: My state has just changed to: 5. Subject: Notifying observers...
  • 中介者模式


中介者模式是一种行为设计模式, 能够减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行合作。

举个现实的例子,航班与航班之间不会直接沟通,而是与塔台沟通,从而可来避免航线交叉、重复而可能引起的飞机之间的碰撞。当然现实中还有很多其他的例子,中介者模式其实就是我们字面上理解的中介者的意思。
中介者模式结构:

代码示例:

interface Mediator {
    notify(sender: object, event: string): void;
}
class ConcreteMediator implements Mediator {
    private component1: Component1;
    private component2: Component2;
    constructor(c1: Component1, c2: Component2) {
        this.component1 = c1;
        this.component1.setMediator(this);
        this.component2 = c2;
        this.component2.setMediator(this);
    }
    public notify(sender: object, event: string): void {
        if (event === 'A') {
            console.log('Mediator reacts on A and triggers following operations:');
            this.component2.doC();
        }
        if (event === 'D') {
            console.log('Mediator reacts on D and triggers following operations:');
            this.component1.doB();
            this.component2.doC();
        }
    }
}
class BaseComponent {
    protected mediator: Mediator;
    constructor(mediator?: Mediator) {
        this.mediator = mediator!;
    }
    public setMediator(mediator: Mediator): void {
        this.mediator = mediator;
    }
}
class Component1 extends BaseComponent {
    public doA(): void {
        console.log('Component 1 does A.');
        this.mediator.notify(this, 'A');
    }
    public doB(): void {
        console.log('Component 1 does B.');
        this.mediator.notify(this, 'B');
    }
}
class Component2 extends BaseComponent {
    public doC(): void {
        console.log('Component 2 does C.');
        this.mediator.notify(this, 'C');
    }
    public doD(): void {
        console.log('Component 2 does D.');
        this.mediator.notify(this, 'D');
    }
}
// 客户端代码
const c1 = new Component1();
const c2 = new Component2();
const mediator = new ConcreteMediator(c1, c2);
// 触发操作A
c1.doA(); // Component 1 does A. Mediator reacts on A and triggers following operations: Component 2 does C.
// 触发操作B 
c2.doD(); // Component 2 does D. Mediator reacts on D and triggers following operations: Component 1 does B. Component 2 does C.

程序组件通过特殊的中介者对象进行间接沟通, 达到了减少组件之间依赖关系的目的。


  • 访问者模式


访问者模式是一种行为设计模式, 它能将算法与其所作用的对象隔离开来。


举个现实的例子,一个房地产销售人员,他可以向各种各样的人推销,如果面对富豪,他推销别墅,如果面对高收入人群,他推销普大平层,如果面对普通收入人群,他推销普通高层。


访问者模式结构:


代码示例:

interface Component {
    accept(visitor: Visitor): void;
}
class ConcreteComponentA implements Component {
    public accept(visitor: Visitor): void {
        visitor.visitConcreteComponentA(this);
    }
    public exclusiveMethodOfConcreteComponentA(): string {
        return 'A';
    }
}
class ConcreteComponentB implements Component {
    public accept(visitor: Visitor): void {
        visitor.visitConcreteComponentB(this);
    }
    public specialMethodOfConcreteComponentB(): string {
        return 'B';
    }
}
interface Visitor {
    visitConcreteComponentA(element: ConcreteComponentA): void;
    visitConcreteComponentB(element: ConcreteComponentB): void;
}
class ConcreteVisitor1 implements Visitor {
    public visitConcreteComponentA(element: ConcreteComponentA): void {
        console.log(`${element.exclusiveMethodOfConcreteComponentA()} + ConcreteVisitor1`);
    }
    public visitConcreteComponentB(element: ConcreteComponentB): void {
        console.log(`${element.specialMethodOfConcreteComponentB()} + ConcreteVisitor1`);
    }
}
class ConcreteVisitor2 implements Visitor {
    public visitConcreteComponentA(element: ConcreteComponentA): void {
        console.log(`${element.exclusiveMethodOfConcreteComponentA()} + ConcreteVisitor2`);
    }
    public visitConcreteComponentB(element: ConcreteComponentB): void {
        console.log(`${element.specialMethodOfConcreteComponentB()} + ConcreteVisitor2`);
    }
}
// 客户端代码
function clientCode(components: Component[], visitor: Visitor) {
    // ...
    for (const component of components) {
        component.accept(visitor);
    }
    // ...
}
const components = [
    new ConcreteComponentA(),
    new ConcreteComponentB(),
];
// 通过基础访问者接口,客户端代码与所有的访问者一同工作
const visitor1 = new ConcreteVisitor1();
clientCode(components, visitor1); // A + ConcreteVisitor1 B + ConcreteVisitor1
// 同样的客户端代码可以与不同类型的访问者一同工作
const visitor2 = new ConcreteVisitor2();
clientCode(components, visitor2); // A + ConcreteVisitor2 B + ConcreteVisitor2
  • 状态模式


状态模式是一种行为设计模式, 可以在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。

举个实际的例子,你的手机,有话费状态,可以打电话,无话费状态,不可以打电话。设计上就是不同的状态下所对应的功能不同。
状态模式结构:

代码示例:

class Context {
    private state: State;
    constructor(state: State) {
        this.transitionTo(state);
    }
    public transitionTo(state: State): void {
        console.log(`Context: Transition to ${(<any>state).constructor.name}.`);
        this.state = state;
        this.state.setContext(this);
    }
    public request1(): void {
        this.state.handle1();
    }
    public request2(): void {
        this.state.handle2();
    }
}
abstract class State {
    protected context: Context;
    public setContext(context: Context) {
        this.context = context;
    }
    public abstract handle1(): void;
    public abstract handle2(): void;
}
class ConcreteStateA extends State {
    public handle1(): void {
        console.log('ConcreteStateA handles request1.');
        console.log('ConcreteStateA wants to change the state of the context.');
        this.context.transitionTo(new ConcreteStateB());
    }
    public handle2(): void {
        console.log('ConcreteStateA handles request2.');
    }
}
class ConcreteStateB extends State {
    public handle1(): void {
        console.log('ConcreteStateB handles request1.');
    }
    public handle2(): void {
        console.log('ConcreteStateB handles request2.');
        console.log('ConcreteStateB wants to change the state of the context.');
        this.context.transitionTo(new ConcreteStateA());
    }
}
// 客户端代码
const context = new Context(new ConcreteStateA());
context.request1(); // Context: Transition to ConcreteStateA. ConcreteStateA handles request1. ConcreteStateA wants to change the state of the context.
context.request2(); // Context: Transition to ConcreteStateB. ConcreteStateB handles request2. ConcreteStateB wants to change the state of the context. Context: Transition to ConcreteStateA.


更多精彩内容,欢迎观看:

前端工程中的设计模式应用(下):https://developer.aliyun.com/article/1396341

相关文章
|
15天前
|
前端开发 JavaScript 安全
前端性能调优:HTTP/2与HTTPS在Web加速中的应用
【10月更文挑战第27天】本文介绍了HTTP/2和HTTPS在前端性能调优中的应用。通过多路复用、服务器推送和头部压缩等特性,HTTP/2显著提升了Web性能。同时,HTTPS确保了数据传输的安全性。文章提供了示例代码,展示了如何使用Node.js创建一个HTTP/2服务器。
29 3
|
16天前
|
Rust 前端开发 JavaScript
前端性能革命:WebAssembly在高性能计算中的应用探索
【10月更文挑战第26天】随着Web应用功能的日益复杂,传统JavaScript解释执行模式逐渐成为性能瓶颈。WebAssembly(Wasm)应运而生,作为一种二进制代码格式,支持C/C++、Rust等语言编写的代码在浏览器中高效运行。Wasm不仅提升了应用的执行速度,还具备跨平台兼容性和安全性,显著改善了Web应用的响应速度和用户体验。
31 4
|
15天前
|
前端开发 数据管理 测试技术
前端自动化测试:Jest与Cypress的实战应用与最佳实践
【10月更文挑战第27天】本文介绍了前端自动化测试中Jest和Cypress的实战应用与最佳实践。Jest适合React应用的单元测试和快照测试,Cypress则擅长端到端测试,模拟用户交互。通过结合使用这两种工具,可以有效提升代码质量和开发效率。最佳实践包括单元测试与集成测试结合、快照测试、并行执行、代码覆盖率分析、测试环境管理和测试数据管理。
31 2
|
16天前
|
前端开发 安全 应用服务中间件
前端性能调优:HTTP/2与HTTPS在Web加速中的应用
【10月更文挑战第26天】随着互联网的快速发展,前端性能调优成为开发者的重要任务。本文探讨了HTTP/2与HTTPS在前端性能优化中的应用,介绍了二进制分帧、多路复用和服务器推送等特性,并通过Nginx配置示例展示了如何启用HTTP/2和HTTPS,以提升Web应用的性能和安全性。
17 3
|
16天前
|
前端开发 JavaScript 数据可视化
前端自动化测试:Jest与Cypress的实战应用与最佳实践
【10月更文挑战第26天】前端自动化测试在现代软件开发中至关重要,Jest和Cypress分别是单元测试和端到端测试的流行工具。本文通过解答一系列问题,介绍Jest与Cypress的实战应用与最佳实践,帮助开发者提高测试效率和代码质量。
27 2
|
16天前
|
前端开发 JavaScript API
前端框架新探索:Svelte在构建高性能Web应用中的优势
【10月更文挑战第26天】近年来,前端技术飞速发展,Svelte凭借独特的编译时优化和简洁的API设计,成为构建高性能Web应用的优选。本文介绍Svelte的特点和优势,包括编译而非虚拟DOM、组件化开发、状态管理及响应式更新机制,并通过示例代码展示其使用方法。
32 2
|
17天前
|
前端开发 JavaScript 开发者
“揭秘React Hooks的神秘面纱:如何掌握这些改变游戏规则的超能力以打造无敌前端应用”
【10月更文挑战第25天】React Hooks 自 2018 年推出以来,已成为 React 功能组件的重要组成部分。本文全面解析了 React Hooks 的核心概念,包括 `useState` 和 `useEffect` 的使用方法,并提供了最佳实践,如避免过度使用 Hooks、保持 Hooks 调用顺序一致、使用 `useReducer` 管理复杂状态逻辑、自定义 Hooks 封装复用逻辑等,帮助开发者更高效地使用 Hooks,构建健壮且易于维护的 React 应用。
28 2
|
30天前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
127 2
|
30天前
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
37 0
|
30天前
|
人工智能 自然语言处理 运维
前端大模型应用笔记(一):两个指令反过来说大模型就理解不了啦?或许该让第三者插足啦 -通过引入中间LLM预处理用户输入以提高多任务处理能力
本文探讨了在多任务处理场景下,自然语言指令解析的困境及解决方案。通过增加一个LLM解析层,将复杂的指令拆解为多个明确的步骤,明确操作类型与对象识别,处理任务依赖关系,并将自然语言转化为具体的工具命令,从而提高指令解析的准确性和执行效率。

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    42
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    46
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    54
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    62
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    57
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    41
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    106
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78