所以人工智能时代已经到来,这是一个巨大的飞跃,目前,用 const fetch = require('node-fetch') 吐出 Node 代码? (对于今天的 ChatGPT 和 Gemini 来说都是如此)并为循环机器的另一个旋转提供动力,即互联网及其内容。
在内容的融合中,设计模式再次出现
从解释如何在 Node(???) 中应用设计模式的帖子到解释所有详细过时内容的帖子,例如如何在 Java 中应用工厂模式(Java 8 于 2014 年 3 月发布添加了 Lambda) ).
曾经偶然遇到过重构大师吗?
这是您在计算机科学(特别是编程)学习之旅中可能访问过的网站。它的设计模式部分得到了很好的解释,也是多年来通过不同论坛分享最多的部分之一。
如果我们去定义什么是设计模式,我们会发现:
设计模式是常见问题的典型解决方案
在软件设计中。每一个图案都像一张蓝图
您可以自定义以解决特定问题
代码中的设计问题。
那为什么要发这篇文章呢?我的意思是,上面链接的网站上有很多信息;这可能就是全部了。
问题是,我总是很难接受这个定义...“在我的代码中解决特定的设计问题”...在我的代码中?我的代码是否有需要解决的问题?
定义,重新构想,项目中使用的编程语言缺乏的抽象。
简单明了。以防万一您还没有产生共鸣,让我们看一些带有代码的示例。这是 Java(主要是一种面向对象的编程语言)中工厂模式的一个非常简单的实现。
public class ShapeFactory { public Shape createShape(String type) { if (type.equalsIgnoreCase("CIRCLE")) { return new Circle(); } else if (type.equalsIgnoreCase("SQUARE")) { return new Square(); } return null; } }
(2014 年 3 月,以防万一你忘记了) 添加了 Lambda(函数式编程的一个概念),所以我们可以这样做:
Map<String, Supplier<Shape>> shapeFactory = new HashMap<>(); shapeFactory.put("CIRCLE", Circle::new); shapeFactory.put("SQUARE", Square::new); Shape circle = shapeFactory.get("CIRCLE").get();
是的,我知道工厂模式是大多数人一直使用的示例,但是其他模式会发生什么情况呢?在其他编程语言中会发生什么?
这是 Typescript 中的访问者模式:
interface Shape { draw(): void; accept(visitor: ShapeVisitor): void; } class Circle implements Shape { radius: number; constructor(radius: number) { this.radius = radius; } draw() { console.log("Drawing a circle"); } accept(visitor: ShapeVisitor) { visitor.visitCircle(this); } } class Square implements Shape { sideLength: number; constructor(sideLength: number) { this.sideLength = sideLength; } draw() { console.log("Drawing a square"); } accept(visitor: ShapeVisitor) { visitor.visitSquare(this); } } interface ShapeVisitor { visitCircle(circle: Circle): void; visitSquare(square: Square): void; } class AreaCalculator implements ShapeVisitor { private area = 0; visitCircle(circle: Circle) { this.area = Math.PI * circle.radius * circle.radius; console.log(`Circle area: ${this.area}`); } visitSquare(square: Square) { this.area = square.sideLength * square.sideLength; console.log(`Square area: ${this.area}`); } getArea(): number { return this.area; } } // Using the Visitor const circle = new Circle(5); const square = new Square(4); const calculator = new AreaCalculator(); circle.accept(calculator); square.accept(calculator);
反射(语言在运行时检查和操作其自身对象的能力)而不是访问者模式:
interface Shape { draw(): void; } class Circle implements Shape { // ... (same as before) radius: number; } class Square implements Shape { // ... (same as before) sideLength: number; } function calculateArea(shape: Shape) { if (shape instanceof Circle) { const circle = shape as Circle; // Type assertion const area = Math.PI * circle.radius * circle.radius; console.log(`Circle area: ${area}`); } else if (shape instanceof Square) { const square = shape as Square; // Type assertion const area = square.sideLength * square.sideLength; console.log(`Square area: ${area}`); } } const circle = new Circle(5); const square = new Square(4); calculateArea(circle); calculateArea(square);
interface Observer { update(data: any): void; } class NewsPublisher { private observers: Observer[] = []; subscribe(observer: Observer) { this.observers.push(observer); } unsubscribe(observer: Observer) { this.observers = this.observers.filter(o => o !== observer); } notify(news: string) { this.observers.forEach(observer => observer.update(news)); } } class NewsletterSubscriber implements Observer { update(news: string) { console.log(`Received news: ${news}`); } } // Using the Observer const publisher = new NewsPublisher(); const subscriber1 = new NewsletterSubscriber(); const subscriber2 = new NewsletterSubscriber(); publisher.subscribe(subscriber1); publisher.subscribe(subscriber2); publisher.notify("New product launched!");
public class ShapeFactory { public Shape createShape(String type) { if (type.equalsIgnoreCase("CIRCLE")) { return new Circle(); } else if (type.equalsIgnoreCase("SQUARE")) { return new Square(); } return null; } }
那时,您可能已经意识到“问题”是 OOP 实现,并且您是完全正确的,但不完全。
每种编程范式,特别是当采用最纯粹的形式时,都有其怪癖、困难或“无法直线实现的事情”,如果你愿意的话。
让我们进入函数式编程领域。您可能听说过 Monad。
无论您是否陷入数学定义的思维陷阱,我们(软件开发人员)也可以将 Monad 理解为设计模式。这是因为在纯函数的世界里,不会发生任何意外,很难想象副作用,但大多数软件产品都需要副作用,那么我们如何...?
这是 Haskell 中 IO Monad 的示例:
Map<String, Supplier<Shape>> shapeFactory = new HashMap<>(); shapeFactory.put("CIRCLE", Circle::new); shapeFactory.put("SQUARE", Square::new); Shape circle = shapeFactory.get("CIRCLE").get();
副作用(读取文件)包含在 IO monad 中。
让我们使用 typescript 添加一个单子示例;
interface Shape { draw(): void; accept(visitor: ShapeVisitor): void; } class Circle implements Shape { radius: number; constructor(radius: number) { this.radius = radius; } draw() { console.log("Drawing a circle"); } accept(visitor: ShapeVisitor) { visitor.visitCircle(this); } } class Square implements Shape { sideLength: number; constructor(sideLength: number) { this.sideLength = sideLength; } draw() { console.log("Drawing a square"); } accept(visitor: ShapeVisitor) { visitor.visitSquare(this); } } interface ShapeVisitor { visitCircle(circle: Circle): void; visitSquare(square: Square): void; } class AreaCalculator implements ShapeVisitor { private area = 0; visitCircle(circle: Circle) { this.area = Math.PI * circle.radius * circle.radius; console.log(`Circle area: ${this.area}`); } visitSquare(square: Square) { this.area = square.sideLength * square.sideLength; console.log(`Square area: ${this.area}`); } getArea(): number { return this.area; } } // Using the Visitor const circle = new Circle(5); const square = new Square(4); const calculator = new AreaCalculator(); circle.accept(calculator); square.accept(calculator);
一个经典的例子,我在互联网上见过这个 Maybe monad 大约 50 次,但它到底是什么?
它试图解决的问题:
interface Shape { draw(): void; } class Circle implements Shape { // ... (same as before) radius: number; } class Square implements Shape { // ... (same as before) sideLength: number; } function calculateArea(shape: Shape) { if (shape instanceof Circle) { const circle = shape as Circle; // Type assertion const area = Math.PI * circle.radius * circle.radius; console.log(`Circle area: ${area}`); } else if (shape instanceof Square) { const square = shape as Square; // Type assertion const area = square.sideLength * square.sideLength; console.log(`Square area: ${area}`); } } const circle = new Circle(5); const square = new Square(4); calculateArea(circle); calculateArea(square);
我们忘记定义对象的属性! ?
在实际用例中,这主要是来自副作用的输入,例如从数据库或文件读取
所以现在如果我们这样做:
interface Observer { update(data: any): void; } class NewsPublisher { private observers: Observer[] = []; subscribe(observer: Observer) { this.observers.push(observer); } unsubscribe(observer: Observer) { this.observers = this.observers.filter(o => o !== observer); } notify(news: string) { this.observers.forEach(observer => observer.update(news)); } } class NewsletterSubscriber implements Observer { update(news: string) { console.log(`Received news: ${news}`); } } // Using the Observer const publisher = new NewsPublisher(); const subscriber1 = new NewsletterSubscriber(); const subscriber2 = new NewsletterSubscriber(); publisher.subscribe(subscriber1); publisher.subscribe(subscriber2); publisher.notify("New product launched!");
程序爆炸了。
没有 Maybe monad 的解决方案:
import { EventEmitter } from 'events'; class NewsPublisher extends EventEmitter { publish(news: string) { this.emit('news', news); } } const publisher = new NewsPublisher(); publisher.on('news', (news) => { console.log(`All subscribers received the news: ${news}`); }); publisher.publish("New product launched!");
程序不会爆炸。
由于可选的链接运算符,maybe monad 在 JavaScript 或 typescript 中不是必需的,但如果你使用的语言没有实现它......那么,你可以应用 Maybe monad 或我该说设计模式吗?
是的,我知道,有些人刚刚学会了 Maybe 的东西,并热切地将其立即应用到 6 个副项目中,而现在我在聚会上因为告诉你“你不需要它”而咯咯笑。不过你仍然可以使用它,事实上,如果你觉得它很酷,我邀请你这样做(在一天结束时,这是你的代码,你可以做任何你想做的事!?)
但回到基础。其他范式又如何呢?如果您跳出了 OOP/FP 的框框思考,我喜欢它!
所有范例肯定都有自己的重复出现的解决方案和技术,即使它们并不总是正式称为“设计模式”。
这里有一些例子(感谢双子座避免了我的思考,感谢我漂亮的格式和附加值?):
有很多“技术”和“模式”,这个列表只是为了给你提供一些线索,如果你好奇的话。
希望您觉得本文有用,请尽快阅读!
虽然术语“设计模式”与 OOP 联系最紧密,但其他范式也有自己的一套重复出现的解决方案和技术。这些技术解决了这些范式的具体挑战和限制,为常见问题提供了既定的方法。因此,即使它们并不总是被正式标记为“设计模式”,它们也具有类似的目的,可以指导开发人员找到有效且可维护的解决方案。
我们可以将设计模式理解为众所周知的解决方法,用于修补我们正在使用的编程语言缺乏抽象的功能。
这篇文章几乎完全由我撰写,指定示例由 Gemini 1.5 Pro
以上是揭秘设计模式的详细内容。更多信息请关注PHP中文网其他相关文章!