所以人工智慧時代已經到來,這是一個巨大的飛躍,目前,用 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中文網其他相關文章!