詳解Java中的五種設(shè)計模式
設(shè)計模式是一種可重用的解決方案,用于解決軟件設(shè)計中常見的問題。不同類型的設(shè)計模式針對解決不同的特定問題或問題組合。
如下圖所示,一些常見的設(shè)計模式類型包括處理對象創(chuàng)建的創(chuàng)建型模式;處理對象組合和組織的結(jié)構(gòu)型模式;以及處理對象和類之間通信的行為型模式。
本文分享幾種與Java中常用的創(chuàng)建型設(shè)計模式相關(guān)的代碼示例。
創(chuàng)建型設(shè)計模式
創(chuàng)建型設(shè)計模式提供了各種對象創(chuàng)建機(jī)制,從而增加了現(xiàn)有代碼的靈活性和重用性。
其主要功能是以最佳方式提供非常具體的解決方案。它們可以進(jìn)一步分為以下類別。
1. 單例
單例是一種創(chuàng)建型設(shè)計模式,它確保一個類只有一個實(shí)例,并提供對該實(shí)例的全局訪問點(diǎn)。
單例模式基于對象只有一個實(shí)例的概念,從而實(shí)現(xiàn)對資源的全局控制。簡而言之,單例設(shè)計模式確保只創(chuàng)建一個類的實(shí)例,并且該實(shí)例在應(yīng)用程序內(nèi)可以全局訪問。
public class SingletonClass {
private static SingletonClass instance;
private SingletonClass() {
// 私有構(gòu)造函數(shù),防止外部實(shí)例化
}
public static SingletonClass getInstance() {
if (instance == null) {
instance = new SingletonClass();
}
return instance;
}
}
如下所示,當(dāng)我們發(fā)送Postman請求時,控制器類和結(jié)果將是同一個實(shí)例:
@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();
}
}
當(dāng)您想要確保類僅存在一個實(shí)例時(例如,由程序的不同部分共享的單個數(shù)據(jù)庫對象),您應(yīng)該使用單例設(shè)計模式。
2. 工廠
工廠方法是一種創(chuàng)建型設(shè)計模式,它提供了一種在創(chuàng)建過程中無需指定其具體類即可創(chuàng)建產(chǎn)品對象的解決方案。
以下是Java代碼示例,PaymentProcessor是定義處理付款的合同的接口。
public interface PaymentProcessor {
void processPayment();
}
CreditCardPaymentProcessor和PaypalPaymentProcessor是實(shí)現(xiàn)PaymentProcessor接口的具體類。這些類為CreditCard和PayPal付款特定的processPayment()方法提供了實(shí)現(xiàn)。
@Service
public class CreditCardPaymentProcessor implements PaymentProcessor {
@Override
public void processPayment() {
// 信用卡支付交易
}
}
@Service
public class PaypalPaymentProcessor implements PaymentProcessor {
@Override
public void processPayment() {
// PayPal支付交易
}
}
PaymentProcessorFactory是實(shí)現(xiàn)工廠設(shè)計模式的工廠類。該類負(fù)責(zé)根據(jù)給定的付款方式創(chuàng)建不同PaymentProcessor實(shí)現(xiàn)的實(shí)例。
@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);
}
}
入口點(diǎn)處理對/processPayment/{paymentMethod}的請求,并使用PaymentProcessorFactory根據(jù)提供的paymentMethod創(chuàng)建適當(dāng)?shù)母犊钐幚砥?。這簡化了代碼并使添加新付款處理器變得容易。
工廠方法是一種用于節(jié)省系統(tǒng)資源的設(shè)計模式,它通過重復(fù)使用現(xiàn)有對象而不是重復(fù)構(gòu)建它們來實(shí)現(xiàn)這一目的。
3. 抽象工廠
抽象工廠是一種創(chuàng)建型設(shè)計模式,它允許您生成相關(guān)對象系列,無需指定其具體類。
以下是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();
}
}
//產(chǎn)品類
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 創(chuàng)建產(chǎn)品 A
ProductFactory productAFactory = new ProductAFactory();
Product productA = productAFactory.createProduct();
System.out.println("Product A: " + productA.getName());
// 使用 ProductBFactory 創(chuàng)建產(chǎn)品 B
ProductFactory productBFactory = new ProductBFactory();
Product productB = productBFactory.createProduct();
System.out.println("Product B: " + productB.getName());
抽象工廠模式在處理不同組相關(guān)項(xiàng)目時非常有用,它可以避免代碼依賴于這些項(xiàng)目的特定類型。您可能事先不知道這些類型,或者希望為將來添加更多類型留出空間。這樣,您的代碼可以更加靈活和可擴(kuò)展。
4. Builder
Builder是一種創(chuàng)建型設(shè)計模式,它允許您以逐步構(gòu)建的方式創(chuàng)建復(fù)雜的對象。通過使用Builder模式,您可以使用相同的構(gòu)建代碼來生成不同類型和表示形式的對象。這種靈活性使得對象的構(gòu)建過程更加可控和可定制。
以下是Java代碼示例::
@Builder
@Getter
@Setter
public class Beer {
//必填屬性
private String name;
private double drinkSize;
private double alcoholPercentage;
private double price;
// 其他屬性
private String brewery; // 生產(chǎn)啤酒的釀酒廠
private String countryOfOrigin; // 啤酒原產(chǎn)國
private String description; // 對啤酒特點(diǎn)的簡要描述
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();
}
}
優(yōu)點(diǎn):
- 減少構(gòu)造函數(shù)中的參數(shù)數(shù)量并提供可讀的方法調(diào)用。
- 允許在完整狀態(tài)下實(shí)例化對象。
- 簡化了不可變對象的構(gòu)建過程。
缺點(diǎn):
- 它會增加代碼行數(shù),但提供了設(shè)計靈活性和改進(jìn)的代碼可讀性。
- 需要為每種產(chǎn)品類型創(chuàng)建單獨(dú)的ConcreteBuilder類。
5. 原型
原型是一種創(chuàng)建型設(shè)計模式,它允許您復(fù)制現(xiàn)有對象,而不依賴于它們的具體類。
以下是Java代碼示例:
designpatterns
└── creational
└── prototype
├── controller
│ └── TreeController.java
├── model
│ ├── Tree.java
│ ├── PlasticTree.java
│ └── PineTree.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() {
//實(shí)現(xiàn)
}
}
//具體類-塑料樹
public PlasticTree() {
setType("Plastic Tree");
}
@Override
public void copy() {
//實(shí)現(xiàn)
}
@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();
}
}
當(dāng)需要創(chuàng)建的新對象與現(xiàn)有對象僅存在輕微差異時,原型模式非常有用。通過提前設(shè)置具有正確設(shè)置的實(shí)例,我們可以在需要更多相似對象時進(jìn)行復(fù)制,從而節(jié)省了創(chuàng)建對象的時間和資源。