设计模式是针对常见软件设计问题的可重用解决方案。它们提供了一种以一致且高效的方式组织和构建代码的方法。一些常见的设计模式包括:
工厂模式是一种创建型设计模式,它提供用于在超类中创建对象的接口,但允许子类更改将要创建的对象的类型。
抽象工厂模式是一种创建型设计模式,它提供了一个接口来创建相关或依赖对象的系列,而无需指定它们的具体类。
Builder模式是一种创建型设计模式,它将复杂对象的构造与其表示分离,允许相同的构造过程创建不同的表示。
策略模式是一种行为设计模式,可以在运行时选择算法的行为。
Decorator模式是一种结构设计模式,允许将行为静态或动态地添加到单个对象,而不影响同一类中其他对象的行为。
Singleton模式是一种创建型设计模式,可确保一个类只有一个实例,同时还提供了对该实例的全局访问点。
观察者模式是一种行为设计模式,允许一个对象(主体)在其状态发生变化时通知其他对象(观察者)。
这些模式很有用,因为它们为开发人员提供了一种通用语言,并且可以使代码更易于维护和理解。
下面是 6 种最常用的设计模式以及 Java 中的示例。
工厂模式
工厂模式是一种创建型设计模式,它提供了一种创建对象的方法,而无需指定将要创建的对象的确切类。它允许一个类将创建对象的责任委托给它的子类。
下面是如何在 Java 中实现工厂模式的示例:
interface Shape {
void draw();
}
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a rectangle");
}
}
class Square implements Shape {
@Override
public void draw() {
System.out.println("Drawing a square");
}
}
class ShapeFactory {
public Shape getShape(String shapeType) {
if (shapeType == null) {
return null;
}
if (shapeType.equalsIgnoreCase("RECTANGLE")) {
return new Rectangle();
} else if (shapeType.equalsIgnoreCase("SQUARE")) {
return new Square();
}
return null;
}
}
在上面的示例中,ShapeFactory类是根据客户端提供的输入创建不同具体类( Rectangle和Square )对象的工厂类。客户端使用工厂类来创建对象,不需要知道将要创建的对象的具体类。
下面是客户端代码如何使用工厂模式创建对象的示例:
ShapeFactory shapeFactory = new ShapeFactory();
//get an object of Rectangle and call its draw method.
Shape shape1 = shapeFactory.getShape("RECTANGLE");
//call draw method of Rectangle
shape1.draw();
//get an object of Square and call its draw method.
Shape shape2 = shapeFactory.getShape("SQUARE");
//call draw method of square
shape2.draw();
在此示例中,客户端可以通过向工厂类提供不同的输入来创建不同的形状对象,而无需知道将要创建的对象的具体类。这允许代码的灵活性,并使得在不修改现有代码的情况下添加新类变得更加容易。
建造者模式
建造者模式是一种创造型设计模式,允许以清晰和有组织的方式逐步完成复杂对象的构造。它将对象的构造与其表示分离,使得在不影响客户端代码的情况下更容易更改对象的内部表示。
以下是如何在 Java 中实现构建器模式的示例:
class Computer {
private String CPU;
private String RAM;
private String GPU;
private String storage;
private Computer(ComputerBuilder builder) {
this.CPU = builder.CPU;
this.RAM = builder.RAM;
this.GPU = builder.GPU;
this.storage = builder.storage;
}
public String getCPU() {
return CPU;
}
public String getRAM() {
return RAM;
}
public String getGPU() {
return GPU;
}
public String getStorage() {
return storage;
}
public static class ComputerBuilder {
private String CPU;
private String RAM;
private String GPU;
private String storage;
public ComputerBuilder setCPU(String CPU) {
this.CPU = CPU;
return this;
}
public ComputerBuilder setRAM(String RAM) {
this.RAM = RAM;
return this;
}
public ComputerBuilder setGPU(String GPU) {
this.GPU = GPU;
return this;
}
public ComputerBuilder setStorage(String storage) {
this.storage = storage;
return this;
}
public Computer build() {
return new Computer(this);
}
}
}
在此示例中,Computer类表示正在构建的复杂对象,而ComputerBuilder类是逐步构建Computer对象的构建器类。ComputerBuilder类具有用于Computer类中每个字段的setter 方法,以及一个返回构造的Computer对象的build()方法。
下面是客户端代码如何使用构建器模式创建Computer对象的示例:
Computer computer = new Computer.ComputerBuilder()
.setCPU("i7")
.setRAM("16GB")
.setGPU("GTX 1080")
.setStorage("1TB")
.build();
在此示例中,客户端可以通过使用构建器类以逐步的方式为每个字段提供不同的值来创建Computer对象。这使代码更具可读性和易于理解,因为客户端不必担心Computer对象的内部表示。
策略设计模式
策略模式是一种行为设计模式,允许在运行时选择算法。它定义了一系列算法,封装了每一个算法,并使它们可以互换。这允许算法独立于使用它的客户端而变化。
以下是如何在 Java 中实现策略模式的示例:
interface PaymentStrategy {
void pay(int amount);
}
class CreditCardStrategy implements PaymentStrategy {
private String name;
private String cardNumber;
private String cvv;
private String dateOfExpiry;
public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate){
this.name=nm;
this.cardNumber=ccNum;
this.cvv=cvv;
this.dateOfExpiry=expiryDate;
}
@Override
public void pay(int amount) {
System.out.println(amount + " paid with credit/debit card");
}
}
class PayPalStrategy implements PaymentStrategy {
private String emailId;
private String password;
public PayPalStrategy(String email, String pwd){
this.emailId=email;
this.password=pwd;
}
@Override
public void pay(int amount) {
System.out.println(amount + " paid using PayPal.");
}
}
class ShoppingCart {
List<Item> items;
PaymentStrategy paymentStrategy;
public ShoppingCart(){
this.items=new ArrayList<Item>();
}
public void addItem(Item item){
this.items.add(item);
}
public void removeItem(Item item){
this.items.remove(item);
}
public int calculateTotal(){
int sum = 0;
for(Item item : items){
sum += item.getPrice();
}
return sum;
}
public void pay(){
int amount = calculateTotal();
paymentStrategy.pay(amount);
}
public void setPaymentStrategy(PaymentStrategy paymentMethod){
this.paymentStrategy=paymentMethod;
}
}
在此示例中,PaymentStrategy接口定义了用于进行支付的支付方法。CreditCardStrategy和PayPalStrategy类是此接口的具体实现,它们提供不同的支付方式(即使用信用卡/借记卡或 PayPal)。ShoppingCart类是使用PaymentStrategy接口进行支付的客户端。ShoppingCart类可以使用setPaymentStrategy方法在运行时设置支付策略。
下面是客户端代码如何使用策略模式的示例:
ShoppingCart cart = new ShoppingCart();
cart.addItem(new Item("item1", 100));
cart.addItem(new Item("item2", 50));
// Selecting the CreditCardStrategy
cart.setPaymentStrategy(new CreditCardStrategy("John Doe","1234567890123456", "123", "12/2022"));
cart.pay();
// Selecting the PayPalStrategy
cart.setPaymentStrategy(new PayPalStrategy("test@example.com", "password"));
cart.pay();
在此示例中,客户端创建了ShoppingCart类的实例并向其中添加了一些项目。然后,客户端通过使用setPaymentStrategy方法在ShoppingCart对象上设置来选择支付策略。这可以在运行时完成,因此客户端可以根据需要在不同的支付策略之间切换。最后,客户端调用ShoppingCart对象的 pay() 方法以使用选定的策略进行支付。
在此示例中,客户端代码可以在信用卡和 PayPal 支付方式之间切换,但也可以包括其他类型的支付方式,例如银行转账等。使用此模式,客户端代码无需担心每次支付的细节方法,它只需要知道公共的PaymentStrategy接口和实现它的具体类就可以支付。
装饰者模式
装饰器模式是一种结构设计模式,它允许通过用装饰器对象包装它或通过使用附加功能扩展它来动态地向单个对象添加行为。装饰器模式允许创建灵活且可重用的代码。
下面是如何在 Java 中实现装饰器模式的示例:
interface Shape {
void draw();
}
class Circle implements Shape {
public void draw() {
System.out.println("Drawing Circle");
}
}
abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}
public void draw(){
decoratedShape.draw();
}
}
class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);
}
@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);
}
private void setRedBorder(Shape decoratedShape){
System.out.println("Border Color: Red");
}
}
在此示例中,Shape接口定义了用于绘制形状的draw()方法。Circle类是此接口的具体实现,它提供绘制圆的行为。ShapeDecorator是一个抽象类,它也实现了 Shape 接口,但它有一个附加的decoratedShape属性,该属性引用它正在装饰的形状。RedShapeDecorator类是一个具体的装饰器,它向它装饰的形状添加一个红色边框。
下面是客户端代码如何使用装饰器模式的示例:
Shape circle = new Circle();
Shape redCircle = new RedShapeDecorator(new Circle());
circle.draw();
redCircle.draw();
在此示例中,客户端创建Circle类的实例,然后创建RedShapeDecorator类的实例,将Circle实例作为参数传递。RedShapeDecorator类包装了Circle实例并添加了绘制红色边框的附加行为。然后,客户端可以对circle和redCircle对象调用draw()方法, Circle类的行为将使用RedShapeDecorator类提供的附加行为进行修饰。
在此示例中,我们使用装饰器模式向形状添加红色边框,但您可以使用此模式向装饰对象添加或修改其他功能或行为。这种模式的关键是客户端不需要知道装饰类,只需要知道被装饰对象的接口即可。
单例模式
单例模式是一种创建型设计模式,它确保一个类只有一个实例,同时也为这个实例提供一个全局访问点。单例模式用于类的单个实例必须在整个执行过程中控制操作的情况。
下面是如何在 Java 中实现单例模式的示例:
class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
public void doSomething() {
// some code
}
}
在这个例子中,Singleton类有一个私有构造函数,这意味着该类不能从类外部实例化。该类还有一个静态实例属性,它将保存该类的单个实例。getInstance()方法用于获取类的单个实例,它使用惰性初始化仅在第一次需要实例时才创建实例。
下面是客户端代码如何使用单例模式的示例:
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton1 == singleton2); // true
在本例中,客户端代码调用了两次getInstance()方法,但它只获得了Singleton类的一个实例。== 运算符用于比较两个实例的引用,它返回 true,因为它们是同一个实例。
当你想确保一个类只被实例化一次并且有一个全局可访问的实例时,单例模式很有用。当您想要控制资源或类实例的数量并且想要对其实施单点控制时,它也很有用。
重要的是要注意单例模式默认情况下不是线程安全的。如果多个线程同时访问getInstance()方法,则可能会创建 Singleton 类的多个实例。要使单例模式线程安全,您可以在getInstance方法上使用 synchronized 关键字,或者可以使用双重检查锁定模式。
观察者模式
观察者模式是一种行为设计模式,允许对象(主体)在其状态发生变化时通知其他对象(观察者)。观察者模式用于需要通知一个对象另一个对象的状态更改的情况,而两个对象之间没有直接引用。
以下是如何在 Java 中实现观察者模式的示例:
interface Observer {
void update(String message);
}
class ConcreteObserver implements Observer {
public void update(String message) {
System.out.println("Received message: " + message);
}
}
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private String message;
public void registerObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(message);
}
}
public void setMessage(String message) {
this.message = message;
notifyObservers();
}
}
在此示例中,Observer接口定义了update()方法,当主体的状态发生变化时将调用该方法。ConcreteObserver类是 Observer 接口的具体实现,它提供处理更新的行为。
Subject接口定义了注册和移除观察者的方法,以及在主题状态发生变化时通知所有注册观察者的方法。ConcreteSubject类是 Subject 接口的具体实现,它维护一个观察者列表并提供注册和删除观察者的方法,以及在主题状态发生变化时通知所有注册观察者的方法。
下面是客户端代码如何使用观察者模式的示例:
ConcreteSubject subject = new ConcreteSubject();
Observer observer = new ConcreteObserver();
subject.registerObserver(observer);
subject.setMessage("Hello World!");
在此示例中,客户端代码创建了一个ConcreteSubject类的实例和一个ConcreteObserver类的实例。然后使用registerObserver()方法向主题注册观察者。客户端然后使用setMessage()设置主题的消息
总之,设计模式是软件开发的重要组成部分,它们帮助开发人员解决常见问题并使代码更易于维护、可重用和可扩展。理解和使用设计模式可以帮助开发人员编写更好、更高效的代码。重要的是要注意,设计模式不是一种放之四海而皆准的解决方案,在应用特定模式之前了解问题和上下文至关重要。