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

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

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

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


  • 备忘录模式


备忘录模式是一种行为设计模式, 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态,允许生成对象状态的快照并在以后将其还原,它不会影响它所处理的对象的内部结构, 也不会影响快照中保存的数据。
备忘录模式结构:

代码示例:

class Originator {
    private state: string;
    constructor(state: string) {
        this.state = state;
        console.log(`Originator: My initial state is: ${state}`);
    }
    public doSomething(): void {
        console.log('Originator: I\'m doing something important.');
        this.state = this.generateRandomString(30);
        console.log(`Originator: and my state has changed to: ${this.state}`);
    }
    private generateRandomString(length: number = 10): string {
        const charSet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        return Array
            .apply(null, { length })
            .map(() => charSet.charAt(Math.floor(Math.random() * charSet.length)))
            .join('');
    }
    public save(): Memento {
        return new ConcreteMemento(this.state);
    }
    public restore(memento: Memento): void {
        this.state = memento.getState();
        console.log(`Originator: My state has changed to: ${this.state}`);
    }
}
interface Memento {
    getState(): string;
    getName(): string;
    getDate(): string;
}
class ConcreteMemento implements Memento {
    private state: string;
    private date: string;
    constructor(state: string) {
        this.state = state;
        this.date = new Date().toISOString().slice(0, 19).replace('T', ' ');
    }
    public getState(): string {
        return this.state;
    }
    public getName(): string {
        return `${this.date} / (${this.state.substr(0, 9)}...)`;
    }
    public getDate(): string {
        return this.date;
    }
}
class Caretaker {
    private mementos: Memento[] = [];
    private originator: Originator;
    constructor(originator: Originator) {
        this.originator = originator;
    }
    public backup(): void {
        console.log('\nCaretaker: Saving Originator\'s state...');
        this.mementos.push(this.originator.save());
    }
    public undo(): void {
        if (!this.mementos.length) {
            return;
        }
        const memento = this.mementos.pop();
        console.log(`Caretaker: Restoring state to: ${memento.getName()}`);
        this.originator.restore(memento);
    }
    public showHistory(): void {
        console.log('Caretaker: Here\'s the list of mementos:');
        for (const memento of this.mementos) {
            console.log(memento.getName());
        }
    }
}
// 客户端代码
const originator = new Originator('Super-duper-super-puper-super.');
const caretaker = new Caretaker(originator);
caretaker.backup();
originator.doSomething();
caretaker.backup();
originator.doSomething();
caretaker.backup();
originator.doSomething();
console.log('');
caretaker.showHistory();
console.log('\nClient: Now, let\'s rollback!\n');
caretaker.undo();
console.log('\nClient: Once more!\n');
caretaker.undo();
Originator: My initial state is: Super-duper-super-puper-super.
Caretaker: Saving Originator's state...
Originator: I'm doing something important.
Originator: and my state has changed to: qXqxgTcLSCeLYdcgElOghOFhPGfMxo
Caretaker: Saving Originator's state...
Originator: I'm doing something important.
Originator: and my state has changed to: iaVCJVryJwWwbipieensfodeMSWvUY
Caretaker: Saving Originator's state...
Originator: I'm doing something important.
Originator: and my state has changed to: oSUxsOCiZEnohBMQEjwnPWJLGnwGmy
Caretaker: Here's the list of mementos:
2019-02-17 15:14:05 / (Super-dup...)
2019-02-17 15:14:05 / (qXqxgTcLS...)
2019-02-17 15:14:05 / (iaVCJVryJ...)
Client: Now, let's rollback!
Caretaker: Restoring state to: 2019-02-17 15:14:05 / (iaVCJVryJ...)
Originator: My state has changed to: iaVCJVryJwWwbipieensfodeMSWvUY
Client: Once more!
Caretaker: Restoring state to: 2019-02-17 15:14:05 / (qXqxgTcLS...)
Originator: My state has changed to: qXqxgTcLSCeLYdcgElOghOFhPGfMxo
  • 策略模式


策略模式是一种行为设计模式, 能让定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。
举个现实的例子,比如赶火车,到达火车站的策略有公交车、地铁、出租车等,我们可以根据预算或时间等因素选择其中的一种策略。
策略模式结构:

代码示例:

class Context {
    private strategy: Strategy;
    constructor(strategy: Strategy) {
        this.strategy = strategy;
    }
    public setStrategy(strategy: Strategy) {
        this.strategy = strategy;
    }
    public doSomeBusinessLogic(): void {
        console.log('Context: Sorting data using the strategy (not sure how it\'ll do it)');
        const result = this.strategy.doAlgorithm(['a', 'b', 'c', 'd', 'e']);
        console.log(result.join(','));
    }
}
interface Strategy {
    doAlgorithm(data: string[]): string[];
}
class ConcreteStrategyA implements Strategy {
    public doAlgorithm(data: string[]): string[] {
        return data.sort();
    }
}
class ConcreteStrategyB implements Strategy {
    public doAlgorithm(data: string[]): string[] {
        return data.reverse();
    }
}
// 客户端代码
const context = new Context(new ConcreteStrategyA());
console.log('Client: Strategy is set to normal sorting.');
context.doSomeBusinessLogic();
console.log('');
console.log('Client: Strategy is set to reverse sorting.');
context.setStrategy(new ConcreteStrategyB());
context.doSomeBusinessLogic();
Client: Strategy is set to normal sorting.
Context: Sorting data using the strategy (not sure how it'll do it)
a,b,c,d,e
Client: Strategy is set to reverse sorting.
Context: Sorting data using the strategy (not sure how it'll do it)
e,d,c,b,a
  • 模板方法模式


模板方法模式是一种行为设计模式, 它在基类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。
举个现实的例子,农村自建房有一套固定的模版方法(比如为:打地基 -> 建造主体 -> 封顶 -> 铺设水电 -> 装修),但这其中可提供几个扩展点, 允许潜在的房屋业主调整成品房屋的部分细节,如装修风格,这使得成品房屋会有不同。

模版方法模式结构:

代码示例:

abstract class AbstractClass {
    public templateMethod(): void {
        this.baseOperation1();
        this.requiredOperations1();
        this.baseOperation2();
        this.hook1();
        this.requiredOperation2();
        this.baseOperation3();
        this.hook2();
    }
    protected baseOperation1(): void {
        console.log('AbstractClass says: I am doing the bulk of the work');
    }
    protected baseOperation2(): void {
        console.log('AbstractClass says: But I let subclasses override some operations');
    }
    protected baseOperation3(): void {
        console.log('AbstractClass says: But I am doing the bulk of the work anyway');
    }
    protected abstract requiredOperations1(): void;
    protected abstract requiredOperation2(): void;
    protected hook1(): void { }
    protected hook2(): void { }
}
class ConcreteClass1 extends AbstractClass {
    protected requiredOperations1(): void {
        console.log('ConcreteClass1 says: Implemented Operation1');
    }
    protected requiredOperation2(): void {
        console.log('ConcreteClass1 says: Implemented Operation2');
    }
}
class ConcreteClass2 extends AbstractClass {
    protected requiredOperations1(): void {
        console.log('ConcreteClass2 says: Implemented Operation1');
    }
    protected requiredOperation2(): void {
        console.log('ConcreteClass2 says: Implemented Operation2');
    }
    protected hook1(): void {
        console.log('ConcreteClass2 says: Overridden Hook1');
    }
}
// 客户端代码
function clientCode(abstractClass: AbstractClass) {
    // ...
    abstractClass.templateMethod();
    // ...
}
console.log('Same client code can work with different subclasses:');
clientCode(new ConcreteClass1());
console.log('');
console.log('Same client code can work with different subclasses:');
clientCode(new ConcreteClass2());
Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass1 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass1 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway
Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass2 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass2 says: Overridden Hook1
ConcreteClass2 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway
  • 职责链模式


职责链模式是一种行为设计模式, 允许将请求沿着处理者链进行发送。收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。


职责链模式结构:


代码示例:

interface Handler {
    setNext(handler: Handler): Handler;
    handle(request: string): string;
}
abstract class AbstractHandler implements Handler
{
    private nextHandler: Handler;
    public setNext(handler: Handler): Handler {
        this.nextHandler = handler;
        return handler;
    }
    public handle(request: string): string {
        if (this.nextHandler) {
            return this.nextHandler.handle(request);
        }
        return null;
    }
}
class MonkeyHandler extends AbstractHandler {
    public handle(request: string): string {
        if (request === 'Banana') {
            return `Monkey: I'll eat the ${request}.`;
        }
        return super.handle(request);
    }
}
class SquirrelHandler extends AbstractHandler {
    public handle(request: string): string {
        if (request === 'Nut') {
            return `Squirrel: I'll eat the ${request}.`;
        }
        return super.handle(request);
    }
}
class DogHandler extends AbstractHandler {
    public handle(request: string): string {
        if (request === 'MeatBall') {
            return `Dog: I'll eat the ${request}.`;
        }
        return super.handle(request);
    }
}
function clientCode(handler: Handler) {
    const foods = ['Nut', 'Banana', 'Cup of coffee'];
    for (const food of foods) {
        console.log(`Client: Who wants a ${food}?`);
        const result = handler.handle(food);
        if (result) {
            console.log(`  ${result}`);
        } else {
            console.log(`  ${food} was left untouched.`);
        }
    }
}
// 客户端代码
const monkey = new MonkeyHandler();
const squirrel = new SquirrelHandler();
const dog = new DogHandler();
monkey.setNext(squirrel).setNext(dog);
console.log('Chain: Monkey > Squirrel > Dog\n');
clientCode(monkey);
console.log('');
console.log('Subchain: Squirrel > Dog\n');
clientCode(squirrel);
Chain: Monkey > Squirrel > Dog
Client: Who wants a Nut?
  Squirrel: I'll eat the Nut.
Client: Who wants a Banana?
  Monkey: I'll eat the Banana.
Client: Who wants a Cup of coffee?
  Cup of coffee was left untouched.
Subchain: Squirrel > Dog
Client: Who wants a Nut?
  Squirrel: I'll eat the Nut.
Client: Who wants a Banana?
  Banana was left untouched.
Client: Who wants a Cup of coffee?
  Cup of coffee was left untouched.
  • 命令模式


命令模式是一种行为设计模式, 它可将请求转换为一个包含与请求相关的所有信息的独立对象。该转换能根据不同的请求将方法参数化、 延迟请求执行或将其放入队列中, 且能实现可撤销操作。


命令模式结构:


代码示例:

interface Command {
    execute(): void;
}
class SimpleCommand implements Command {
    private payload: string;
    constructor(payload: string) {
        this.payload = payload;
    }
    public execute(): void {
        console.log(`SimpleCommand: See, I can do simple things like printing (${this.payload})`);
    }
}
class ComplexCommand implements Command {
    private receiver: Receiver;
    private a: string;
    private b: string;
    constructor(receiver: Receiver, a: string, b: string) {
        this.receiver = receiver;
        this.a = a;
        this.b = b;
    }
    public execute(): void {
        console.log('ComplexCommand: Complex stuff should be done by a receiver object.');
        this.receiver.doSomething(this.a);
        this.receiver.doSomethingElse(this.b);
    }
}
class Receiver {
    public doSomething(a: string): void {
        console.log(`Receiver: Working on (${a}.)`);
    }
    public doSomethingElse(b: string): void {
        console.log(`Receiver: Also working on (${b}.)`);
    }
}
class Invoker {
    private onStart: Command;
    private onFinish: Command;
    public setOnStart(command: Command): void {
        this.onStart = command;
    }
    public setOnFinish(command: Command): void {
        this.onFinish = command;
    }
    public doSomethingImportant(): void {
        console.log('Invoker: Does anybody want something done before I begin?');
        if (this.isCommand(this.onStart)) {
            this.onStart.execute();
        }
        console.log('Invoker: ...doing something really important...');
        console.log('Invoker: Does anybody want something done after I finish?');
        if (this.isCommand(this.onFinish)) {
            this.onFinish.execute();
        }
    }
    private isCommand(object): object is Command {
        return object.execute !== undefined;
    }
}
// 客户端代码
const invoker = new Invoker();
invoker.setOnStart(new SimpleCommand('Say Hi!'));
const receiver = new Receiver();
invoker.setOnFinish(new ComplexCommand(receiver, 'Send email', 'Save report'));
invoker.doSomethingImportant();
Invoker: Does anybody want something done before I begin?
SimpleCommand: See, I can do simple things like printing (Say Hi!)
Invoker: ...doing something really important...
Invoker: Does anybody want something done after I finish?
ComplexCommand: Complex stuff should be done by a receiver object.
Receiver: Working on (Send email.)
Receiver: Also working on (Save report.)

参考文献


Alexander Shvets, Dive-into Design Patterns[M], Finelybook, 2019.


团队介绍

我们是大淘宝技术-营销与平台策略技术-营销产品团队,主要负责淘宝好价、百亿补贴、聚划算、天天特卖等大淘宝核心产品及各类大型的营销会场活动,同时我们也是前端智能化的先锋队,有方舟、千帆、imgcook、智能UI等多种技术产品。


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