关于软件设计模式的理解

系列文章
关于时间复杂度o(1), o(n), o(logn), o(nlogn)的理解

关于HashMap的哈希碰撞、拉链法和key的哈希函数设计

关于JVM内存模型和堆内存模型的理解

关于代理模式的理解

关于Mysql基本概念的理解

关于软件设计模式的理解

文章目录

前言

软件设计模式(Software Design Pattern),是一套被反复使用的、关于代码设计经验的总结。被用来解决一些不断重复发生的问题,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。其目的是为了提高代码的可重用性、代码的可读性和代码的可靠性

一、软件设计模式遵循的六大原则

设计模式通常遵循的六大原则是:

开放封闭原则(Open/Closed Principle,OCP): 软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。这意味着在不修改现有代码逻辑的情况下,能够通过扩展来增加新的功能。

单一职责原则(Single Responsibility Principle,SRP): 一个类应该只负责一种类型的任务或职责。

里氏替换原则(Liskov Substitution Principle,LSP): 子类型必须能够替换掉它们的父类型,而不影响程序的正确性。

依赖倒置原则(Dependency Inversion Principle,DIP): 应该依赖于接口或抽象类,而不是具体的实现。

接口隔离原则(Interface Segregation Principle,ISP): 一个类不应该依赖它不需要的接口。

合成/聚合复用原则(Composition/Aggregation Reuse Principle,CARP): 应该优先使用对象组合或聚合,而不是继承来实现代码复用。

这些原则提供了指导,帮助开发人员设计出灵活、可维护、可扩展和易于理解的软件系统。虽然并不是每种设计模式都严格遵循这些原则,但设计模式通常是以这些原则为基础来提供解决特定问题的通用方案

二、学习软件设计模式的意义

设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。正确使用设计模式具有以下优势。:

  1. 可以提高程序员的思维能力、编程能力和设计能力。
  2. 可以使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
  3. 可以使设计的代码可复用性高、可读性强、可靠性高、灵活性好、可维护性强。

三、使用率最高的设计模式有哪几个?具体使用场景举例

1.单例模式(Singleton)

场景举例: 当系统中需要确保一个类只有一个实例,并提供全局访问点时,通常使用单例模式。如数据库连接池、日志管理器等

代码案例:

步骤 1: 创建单例类

复制代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DatabaseConnection {
    // 数据库连接相关配置
    private static final String URL = "jdbc:mysql://localhost:3306/mydatabase";
    private static final String USERNAME = "username";
    private static final String PASSWORD = "password";

    // 私有静态变量,保存类的唯一实例
    private static DatabaseConnection instance;

    // 数据库连接对象
    private Connection connection;

    // 私有构造函数,防止外部直接创建对象
    private DatabaseConnection() {
        try {
            // 创建数据库连接
            connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    // 公有静态方法,返回唯一实例
    public static DatabaseConnection getInstance() {
        if (instance == null) {
            // 确保线程安全
            synchronized (DatabaseConnection.class) {
                if (instance == null) {
                    instance = new DatabaseConnection();
                }
            }
        }
        return instance;
    }

    // 获取数据库连接对象
    public Connection getConnection() {
        return connection;
    }
}

步骤 2: 使用单例类

复制代码
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Main {
    public static void main(String[] args) {
        // 获取数据库连接
        Connection connection = DatabaseConnection.getInstance().getConnection();
        
        // 执行数据库操作
        try {
            PreparedStatement statement = connection.prepareStatement("SELECT * FROM users");
            ResultSet resultSet = statement.executeQuery();
            while (resultSet.next()) {
                System.out.println("User ID: " + resultSet.getInt("id") + ", Name: " + resultSet.getString("name"));
            }
            resultSet.close();
            statement.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

解释
单例模式的核心: 私有构造函数和一个返回实例的公有静态方法。
线程安全: 使用双重检查锁定确保在多线程环境下安全创建实例。
延迟初始化: 实例在类被加载时不会创建,在首次需要时才创建,节省资源。
数据库连接池: 这种方式也可以用于实现简单的数据库连接池,通过控制并发访问来管理连接数,提高数据库连接的效率和资源利用率。

这种实现方式在实际应用中非常有用,特别是在需要频繁访问数据库的情况下,可以减少连接的开销和管理成本。

2.工厂模式(Factory)

场景举例: 当需要创建多个具有相似功能的对象时,使用工厂模式可以将对象的创建逻辑封装在一个工厂类中,提高代码的灵活性和可维护性。如数据库驱动管理等

代码案例:

步骤 1: 创建接口

复制代码
import java.sql.Connection;

public interface DatabaseConnection {
    Connection getConnection();
}

步骤 2: 创建具体实现类

复制代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class MySQLConnection implements DatabaseConnection {
    // MySQL数据库连接相关配置
    private static final String URL = "jdbc:mysql://localhost:3306/mydatabase";
    private static final String USERNAME = "username";
    private static final String PASSWORD = "password";

    @Override
    public Connection getConnection() {
        Connection connection = null;
        try {
            // 创建MySQL数据库连接
            connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
}

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class PostgreSQLConnection implements DatabaseConnection {
    // PostgreSQL数据库连接相关配置
    private static final String URL = "jdbc:postgresql://localhost:5432/mydatabase";
    private static final String USERNAME = "username";
    private static final String PASSWORD = "password";

    @Override
    public Connection getConnection() {
        Connection connection = null;
        try {
            // 创建PostgreSQL数据库连接
            connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
}

步骤 3: 创建工厂类

复制代码
public class ConnectionFactory {
    public static DatabaseConnection getDatabaseConnection(String dbType) {
        if (dbType.equalsIgnoreCase("MySQL")) {
            return new MySQLConnection();
        } else if (dbType.equalsIgnoreCase("PostgreSQL")) {
            return new PostgreSQLConnection();
        }
        return null;
    }
}

步骤 4: 使用工厂模式获取数据库连接

复制代码
import java.sql.Connection;

public class Main {
    public static void main(String[] args) {
        // 获取MySQL数据库连接
        DatabaseConnection mysqlConnection = ConnectionFactory.getDatabaseConnection("MySQL");
        Connection mysqlConn = mysqlConnection.getConnection();
        
        // 获取PostgreSQL数据库连接
        DatabaseConnection postgresConnection = ConnectionFactory.getDatabaseConnection("PostgreSQL");
        Connection postgresConn = postgresConnection.getConnection();
        
        // 使用数据库连接执行操作...
    }
}

解释
工厂模式的核心: 根据条件动态创建对象,将创建逻辑封装在工厂类中,客户端无需关心具体的创建细节。
可扩展性: 当需要新增其他类型的数据库连接时,只需在工厂类中添加相应的创建逻辑即可,不需要修改客户端代码。
解耦: 客户端与具体数据库连接类之间解耦,通过工厂类进行统一管理,降低了代码的耦合度。

工厂模式能够很好地应对数据库驱动管理场景中的需求变化,使得代码更加灵活和可维护。

3.观察者模式(Observer)

场景举例: 当一个对象的状态发生改变时,需要通知其他相关对象,并自动更新它们的状态时,通常使用观察者模式。如消息订阅与发布系统等

代码案例:

步骤 1: 创建主题接口

首先,定义一个主题接口,用于注册、删除和通知观察者。

复制代码
public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

步骤 2: 创建观察者接口

然后,定义一个观察者接口,用于接收主题的通知。

复制代码
public interface Observer {
    void update(String message);
}

步骤 3: 创建具体主题类

接下来,创建具体的主题类,实现主题接口,并维护观察者列表,以及在状态变化时通知观察者。

复制代码
import java.util.ArrayList;
import java.util.List;

public class MessageTopic implements Subject {
    private List<Observer> observers;
    private String message;

    public MessageTopic() {
        this.observers = new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }

    public void setMessage(String message) {
        this.message = message;
        notifyObservers();
    }
}

步骤 4: 创建具体观察者类

然后,创建具体的观察者类,实现观察者接口,并在接收到通知时执行相应的操作。

复制代码
public class MessageSubscriber implements Observer {
    private String name;

    public MessageSubscriber(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " received message: " + message);
    }
}

步骤 5: 使用观察者模式

最后,在应用程序中使用观察者模式。

复制代码
public class Main {
    public static void main(String[] args) {
        // 创建主题
        MessageTopic topic = new MessageTopic();
        
        // 创建观察者
        Observer subscriber1 = new MessageSubscriber("Subscriber 1");
        Observer subscriber2 = new MessageSubscriber("Subscriber 2");
        
        // 注册观察者
        topic.registerObserver(subscriber1);
        topic.registerObserver(subscriber2);
        
        // 发布消息
        topic.setMessage("Hello, world!");
    }
}

解释
主题接口: 定义了注册、删除和通知观察者的方法。
观察者接口: 定义了观察者需要实现的更新方法。
具体主题类: 实现了主题接口,维护了观察者列表,并在状态变化时通知所有观察者。
具体观察者类: 实现了观察者接口,定义了接收通知时的具体行为。
使用观察者模式: 创建主题对象,创建观察者对象并注册到主题中,然后发布消息。所有注册的观察者都会接收到消息通知并执行相应的操作。

观察者模式非常适用于消息订阅与发布场景,可以实现松耦合的通信机制,让发布者和订阅者之间的关系更加灵活。

4.策略模式(Strategy)

场景举例: 当需要在运行时根据不同的情况选择算法或行为时,使用策略模式可以将不同的算法封装成不同的策略类,使得算法的变化独立于使用算法的客户。如支付系统中的支付策略等

代码案例:

步骤 1: 创建支付策略接口

首先,定义一个支付策略接口,用于定义支付的方法。

复制代码
public interface PaymentStrategy {
    void pay(double amount);
}

步骤 2: 创建具体的支付策略类

然后,创建具体的支付策略类,实现支付策略接口,每个具体的支付策略类代表一种支付方式,例如信用卡支付、支付宝支付、微信支付等

复制代码
public class CreditCardPayment implements PaymentStrategy {
    private String cardNumber;
    private String expiryDate;
    private String cvv;

    public CreditCardPayment(String cardNumber, String expiryDate, String cvv) {
        this.cardNumber = cardNumber;
        this.expiryDate = expiryDate;
        this.cvv = cvv;
    }

    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via credit card.");
    }
}

public class AlipayPayment implements PaymentStrategy {
    private String account;

    public AlipayPayment(String account) {
        this.account = account;
    }

    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via Alipay.");
    }
}

public class WechatPayment implements PaymentStrategy {
    private String account;

    public WechatPayment(String account) {
        this.account = account;
    }

    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via WeChat.");
    }
}

步骤 3: 创建上下文类

接下来,创建上下文类,用于持有具体的支付策略对象,并提供支付方法。

复制代码
public class PaymentContext {
    private PaymentStrategy paymentStrategy;

    public PaymentContext(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void pay(double amount) {
        paymentStrategy.pay(amount);
    }
}

步骤 4: 使用策略模式

最后,在应用程序中使用策略模式进行支付。

复制代码
public class Main {
    public static void main(String[] args) {
        // 创建支付上下文
        PaymentContext paymentContext = new PaymentContext(new CreditCardPayment("1234 5678 9012 3456", "12/24", "123"));

        // 进行支付
        paymentContext.pay(100.0);

        // 切换支付方式
        paymentContext.setPaymentStrategy(new AlipayPayment("[email protected]"));

        // 进行支付
        paymentContext.pay(200.0);
    }
}

解释
支付策略接口: 定义了支付的方法。
具体的支付策略类: 实现了支付策略接口,每个类代表一种支付方式,实现了具体的支付逻辑。
支付上下文类: 持有具体的支付策略对象,并提供支付方法,客户端通过上下文类进行支付。
使用策略模式: 创建支付上下文对象,根据需要设置不同的支付策略,然后进行支付操作。

策略模式能够有效地解耦客户端和具体的支付策略,使得支付系统更加灵活,易于扩展和维护。

相关推荐
庄小焱4 小时前
设计模式——中介者设计模式(行为型)
设计模式
庄小焱7 小时前
设计模式——备忘录设计模式(行为型)
设计模式
庄小焱7 小时前
设计模式——代理设计模式(结构型)
设计模式
哆啦A梦的口袋呀7 小时前
基于Python学习《Head First设计模式》第三章 装饰者模式
python·学习·设计模式
哆啦A梦的口袋呀7 小时前
基于Python学习《Head First设计模式》第五章 单件模式
python·学习·设计模式
季鸢8 小时前
Java设计模式之备忘录模式详解
java·设计模式·备忘录模式
摘星编程12 小时前
工厂方法模式深度解析:从原理到应用实战
java·设计模式·软件工程·工厂方法模式
何中应12 小时前
【设计模式-4.7】行为型——备忘录模式
java·设计模式·备忘录模式
suixinger_lmh1 天前
功能结构整理
unity·设计模式·c#·源代码管理
冰茶_1 天前
建造者模式:优雅构建复杂对象
设计模式·微软·c#·.netcore·建造者模式·软件开发