簡介
設計模式是一種可重用的解決方案,用于解決軟件設計中常見的問題。不同類型的設計模式針對解決不同的特定問題或問題組合。
如下圖所示,一些常見的設計模式類型包括處理對象創建的創建型模式;處理對象組合和組織的結構型模式;以及處理對象和類之間通信的行為型模式。
本文分享幾種與JAVA中常用的創建型設計模式相關的代碼示例。
創建型設計模式
創建型設計模式提供了各種對象創建機制,從而增加了現有代碼的靈活性和重用性。
其主要功能是以最佳方式提供非常具體的解決方案。它們可以進一步分為以下類別。
1 單例
單例是一種創建型設計模式,它確保一個類只有一個實例,并提供對該實例的全局訪問點。
單例模式基于對象只有一個實例的概念,從而實現對資源的全局控制。簡而言之,單例設計模式確保只創建一個類的實例,并且該實例在應用程序內可以全局訪問。
public class SingletonClass {
private static SingletonClass instance;
private SingletonClass() {
// 私有構造函數,防止外部實例化
}
public static SingletonClass getInstance() {
if (instance == null) {
instance = new SingletonClass();
}
return instance;
}
}
如下所示,當我們發送Postman請求時,控制器類和結果將是同一個實例:
@RestController
@RequestMApping("/api")
public class SingletonController {
private SingletonClass singletonClass;
public SingletonController(SingletonClass singletonClass) {
this.singletonClass = singletonClass;
}
@GetMapping("/singleton")
public String getSingleton() {
return "This is a singleton instance: " + singletonClass.toString();
}
}
當您想要確保類僅存在一個實例時(例如,由程序的不同部分共享的單個數據庫對象),您應該使用單例設計模式。
2 工廠
工廠方法是一種創建型設計模式,它提供了一種在創建過程中無需指定其具體類即可創建產品對象的解決方案。
以下是Java代碼示例,
PaymentProcessor
是定義處理付款的合同的接口。
public interface PaymentProcessor {
void processPayment();
}
CreditCardPaymentProcessor和PaypalPaymentProcessor是實現PaymentProcessor
接口的具體類。這些類為CreditCard和PayPal付款特定的processPayment()
方法提供了實現。
@Service
public class CreditCardPaymentProcessor implements PaymentProcessor {
@Override
public void processPayment() {
// 信用卡支付交易
}
}
@Service
public class PaypalPaymentProcessor implements PaymentProcessor {
@Override
public void processPayment() {
// PayPal支付交易
}
}
PaymentProcessorFactory
是實現工廠設計模式的工廠類。該類負責根據給定的付款方式創建不同PaymentProcessor
實現的實例。
@Component
public class PaymentProcessorFactory {
private final CreditCardPaymentProcessor creditCardPaymentProcessor;
private final PaypalPaymentProcessor paypalPaymentProcessor;
public PaymentProcessorFactory(CreditCardPaymentProcessor creditCardPaymentProcessor,
PaypalPaymentProcessor paypalPaymentProcessor) {
this.creditCardPaymentProcessor = creditCardPaymentProcessor;
this.paypalPaymentProcessor = paypalPaymentProcessor;
}
public PaymentProcessor createPaymentProcessor(String paymentMethod) {
if (paymentMethod.equalsIgnoreCase("creditcard")) {
return creditCardPaymentProcessor;
} else if (paymentMethod.equalsIgnoreCase("paypal")) {
return paypalPaymentProcessor;
}
throw new IllegalArgumentException("Invalid payment method: " + paymentMethod);
}
}
入口點處理對/processPayment/{paymentMethod}的請求,并使用PaymentProcessorFactory根據提供的paymentMethod創建適當的付款處理器。這簡化了代碼并使添加新付款處理器變得容易。
工廠方法是一種用于節省系統資源的設計模式,它通過重復使用現有對象而不是重復構建它們來實現這一目的。
3 抽象工廠
抽象工廠是一種創建型設計模式,它允許您生成相關對象系列,無需指定其具體類。
以下是Java代碼示例,
//工廠類
public interface ProductFactory {
Product createProduct();
}
public class ProductAFactory implements ProductFactory{
@Override
public Product createProduct() {
return new ProductA();
}
}
public class ProductBFactory implements ProductFactory{
@Override
public Product createProduct() {
return new ProductB();
}
}
//產品類
public interface Product {
String getName();
}
public class ProductA implements Product {
@Override
public String getName() {
return "Product A";
}
}
public class ProductB implements Product {
@Override
public String getName() {
return "Product B";
}
}
// 使用 ProductAFactory 創建產品 A
ProductFactory productAFactory = new ProductAFactory();
Product productA = productAFactory.createProduct();
System.out.println("Product A: " + productA.getName());
// 使用 ProductBFactory 創建產品 B
ProductFactory productBFactory = new ProductBFactory();
Product productB = productBFactory.createProduct();
System.out.println("Product B: " + productB.getName());
抽象工廠模式在處理不同組相關項目時非常有用,它可以避免代碼依賴于這些項目的特定類型。您可能事先不知道這些類型,或者希望為將來添加更多類型留出空間。這樣,您的代碼可以更加靈活和可擴展。
4 Builder
Builder是一種創建型設計模式,它允許您以逐步構建的方式創建復雜的對象。通過使用Builder模式,您可以使用相同的構建代碼來生成不同類型和表示形式的對象。這種靈活性使得對象的構建過程更加可控和可定制。
以下是Java代碼示例,
@Builder
@Getter
@Setter
public class Beer {
//必填屬性
private String name;
private double drinkSize;
private double alcoholPercentage;
private double price;
// 其他屬性
private String brewery; // 生產啤酒的釀酒廠
private String countryOfOrigin; // 啤酒原產國
private String description; // 對啤酒特點的簡要描述
private String packaging; // 包裝類型(瓶裝、罐裝、生啤等)
private String servingTemperature; // 推薦的飲用溫度
private String foodPAIring; // 適合搭配該啤酒的食物
}
@RestController
@RequestMapping("/api/beers")
public class BeerController {
@GetMapping("/basic")
public String createStandardBeer() {
Beer beer = Beer.builder()
.name("Standard Beer")
.drinkSize(500)
.alcoholPercentage(5.0)
.price(5.99)
.build();
return "Created beer: " + beer.getName() +
", Drink Size: " + beer.getDrinkSize() +
", Alcohol Percentage: " + beer.getAlcoholPercentage() +
", Price: " + beer.getPrice();
}
@GetMapping("/premium")
public String createPremiumBeer() {
Beer beer = Beer.builder()
.name("Sample Beer")
.drinkSize(330)
.alcoholPercentage(5.0)
.price(10.99)
.brewery("Crafty Brews")
.countryOfOrigin("United States")
.description("A refreshing lager with a smooth taste.")
.packaging("Bottle")
.servingTemperature("4-6°C")
.foodPairing("Pairs well with grilled chicken and salads.")
.build();
return "Created beer: " + beer.getName() +
", Drink Size: " + beer.getDrinkSize() +
", Alcohol Percentage: " + beer.getAlcoholPercentage() +
", Price: " + beer.getPrice() +
", Brewery: " + beer.getBrewery() +
", Country of Origin: " + beer.getCountryOfOrigin() +
", Description: " + beer.getDescription() +
", Packaging: " + beer.getPackaging() +
", Serving Temperature: " + beer.getServingTemperature() +
", Food Pairing: " + beer.getFoodPairing();
}
優點
-
減少構造函數中的參數數量并提供可讀的方法調用。 -
允許在完整狀態下實例化對象。 -
簡化了不可變對象的構建過程。
缺點
-
它會增加代碼行數,但提供了設計靈活性和改進的代碼可讀性。 -
需要為每種產品類型創建單獨的ConcreteBuilder類。
5 原型
原型是一種創建型設計模式,它允許您復制現有對象,而不依賴于它們的具體類。
以下是Java代碼示例,
designpatterns
└── creational
└── prototype
├── controller
│ └── TreeController.java
├── model
│ ├── Tree.java
│ ├── PlasticTree.java
│ └── P.NETree.java
└── PrototypeDemoApplication.java
//抽象類
@Getter
@Setter
public abstract class Tree implements Cloneable {
private String type;
public abstract void copy();
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
//具體類-松樹
public class PineTree extends Tree {
public PineTree() {
setType("Pine Tree");
}
@Override
public void copy() {
//實現
}
}
//具體類-塑料樹
public PlasticTree() {
setType("Plastic Tree");
}
@Override
public void copy() {
//實現
}
@RestController
@RequestMapping("/api/trees")
public class TreeController {
@GetMapping("/plastic")
public String createPlasticTree() {
Tree plasticTree = new PlasticTree();
return "Created: " + plasticTree.getType();
}
@GetMapping("/pine")
public String createPineTree() {
Tree pineTree = new PineTree();
return "Created: " + pineTree.getType();
}
}
當需要創建的新對象與現有對象僅存在輕微差異時,原型模式非常有用。通過提前設置具有正確設置的實例,我們可以在需要更多相似對象時進行復制,從而節省了創建對象的時間和資源。