常见的设计模式和应用场景(一)
文章目录
- 1.单例模式(Singleton Pattern)
- 1-1.定义
- 1-2.实现示例
- 1-3.应用场景
- 1-4.注意事项
- 2.工厂方法模式(Factory Method Pattern)
- 2-1.定义
- 2-2.实现示例与应用场景
- 3.观察者模式(Observer Pattern)
- 3-1.定义
- 3-2.实现示例
- 3-3.应用场景
设计模式是软件工程中为解决常见问题而总结出的一系列可复用的解决方案。它们是对软件设计中常见结构和交互方式的抽象,帮助开发者更高效地开发、维护代码,并促进代码的可读性和可扩展性。
1.单例模式(Singleton Pattern)
1-1.定义
确保一个类只有一个实例,并提供全局访问点。
1-2.实现示例
- 私有化构造函数
- 静态方法提供实例(懒汉式、饿汉式、双重检查锁等)
以下是双重检查锁的实现方式:
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
1-3.应用场景
全局配置管理(如 ConfigManager)
日志记录器(避免多线程写日志冲突)
数据库连接池(共享唯一资源)
1-4.注意事项
优点:节省资源,统一控制。
缺点:可能引入全局状态,测试困难,需处理线程安全。
为什么需要双重校验锁?
第一次检查:在进入同步代码块之前先检查instance是否为null。如果instance已经初始化,则不需要执行同步代码块,减少了获取锁的开销。
同步块:只有在instance为null时才需要同步。这避免了每次调用getInstance()方法时都需要进行同步,从而提高了程序的性能。
第二次检查:在同步块内再次检查instance是否为null是为了确保只有一个实例被创建,即使存在多个线程同时通过了第一次检查。
volatile关键字:确保了instance变量的可见性和禁止指令重排序优化,避免了多线程环境下可能出现的异常情况。
2.工厂方法模式(Factory Method Pattern)
2-1.定义
工厂方法模式(Factory Method Pattern) 是一种创建型设计模式,它提供了一种创建对象的方式,但允许子类决定实例化哪一个类。工厂方法模式将对象的创建过程延迟到子类中实现。
主要角色:
- Product(抽象产品):定义工厂方法所创建的对象的接口。
- ConcreteProduct(具体产品):实现Product接口的具体类。
- Creator(抽象工厂):声明工厂方法,该方法返回一个Product类型的对象。可以是在Creator中定义一个默认的工厂方法,也可以在子类中重写此方法。
- ConcreteCreator(具体工厂):重写工厂方法以返回一个ConcreteProduct实例。
2-2.实现示例与应用场景
工厂方法模式适用于以下情况:
- 当一个类不能预见它需要创建的对象的类时。
- 当一个类希望它的子类来指定它要创建的对象时。
- 类想让它自己的子类来指定它创建的对象种类时。
例如,在图形用户界面应用中,不同操作系统有不同的窗口样式(如Windows风格、Mac风格等),使用工厂方法模式可以让应用程序根据运行的操作系统类型创建合适的窗口组件。
假设我们正在开发一个应用,该应用需要支持多种数据库(如MySQL、PostgreSQL)。我们可以使用工厂方法模式来抽象出创建数据库连接的逻辑,使得应用可以根据配置或运行时条件选择合适的数据库驱动。
如下为服务端代码
// 抽象产品:定义所有具体产品的公共接口
public interface DatabaseConnection {
void connect();
}
// 具体产品A: MySQL数据库连接
public class MySQLConnection implements DatabaseConnection {
@Override
public void connect() {
System.out.println("Connecting to MySQL database...");
// 这里可以添加具体的连接逻辑,例如加载驱动、建立连接等
}
}
// 具体产品B: PostgreSQL数据库连接
public class PostgreSQLConnection implements DatabaseConnection {
@Override
public void connect() {
System.out.println("Connecting to PostgreSQL database...");
// 这里可以添加具体的连接逻辑
}
}
// 抽象工厂:声明工厂方法,该方法将返回一个DatabaseConnection类型的对象
public abstract class ConnectionFactory {
public abstract DatabaseConnection createConnection();
public void executeQuery(String query) {
DatabaseConnection connection = createConnection();
connection.connect();
// 执行查询操作...
System.out.println("Executing query: " + query);
}
}
// 具体工厂A: 创建MySQL数据库连接
public class MySQLConnectionFactory extends ConnectionFactory {
@Override
public DatabaseConnection createConnection() {
return new MySQLConnection();
}
}
// 具体工厂B: 创建PostgreSQL数据库连接
public class PostgreSQLConnectionFactory extends ConnectionFactory {
@Override
public DatabaseConnection createConnection() {
return new PostgreSQLConnection();
}
}
客户端代码(使用工厂)
public class Client {
public static void main(String[] args) {
// 根据配置或用户输入选择具体的工厂
String dbType = "mysql"; // 假设从配置文件或用户输入获取
ConnectionFactory factory;
if ("mysql".equalsIgnoreCase(dbType)) {
factory = new MySQLConnectionFactory();
} else if ("postgresql".equalsIgnoreCase(dbType)) {
factory = new PostgreSQLConnectionFactory();
} else {
throw new IllegalArgumentException("Unsupported database type");
}
// 使用工厂创建连接并执行查询
factory.executeQuery("SELECT * FROM users");
}
}
在这个例子中:
DatabaseConnection 是抽象产品接口。
MySQLConnection 和 PostgreSQLConnection 是具体产品类。
ConnectionFactory 是抽象工厂,声明了 createConnection() 工厂方法。
MySQLConnectionFactory 和 PostgreSQLConnectionFactory 是具体工厂类,实现了 createConnection() 方法来创建具体的产品实例。
客户端代码根据配置或用户输入选择合适的工厂,然后通过工厂创建数据库连接并执行查询。
这种设计使得系统更加灵活和可扩展,易于添加新的数据库类型而无需修改现有代码。同时,它也隐藏了对象创建的复杂性,简化了客户端代码的实现。
3.观察者模式(Observer Pattern)
3-1.定义
观察者模式(Observer Pattern) 是一种行为设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象发生变化时,它的所有依赖者(观察者)都会收到通知并自动更新。
主要角色:
- Subject(主题/被观察者):知道其观察者,提供注册和删除观察者的接口,并在状态变化时通知它们。
- ConcreteSubject(具体主题):存储有关状态信息,这些状态可能需要被观察者使用。调用它的观察者以通知状态变化。
- Observer(观察者):为那些在主题发生改变时需获得通知的对象定义一个更新接口。
- ConcreteObserver(具体观察者):实现观察者接口,维护一个指向具体主题的引用,并根据主题的状态更新自身。
3-2.实现示例
下面是一个简单的Java示例,展示如何使用观察者模式来实现一个天气预报系统。假设我们有一个气象站,每当气象数据发生变化时,会通知所有的显示设备更新显示内容。
import java.util.ArrayList;
import java.util.List;
// 1. 观察者接口 Observer
public interface Observer {
void update(float temperature, float humidity, float pressure);
}
// 2. 主题接口 Subject
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
// 3. 具体的主题类 WeatherData
public class WeatherData implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
public void measurementsChanged() {
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
// 4. 具体的观察者类 CurrentConditionsDisplay
public class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
}
}
客户端代码:
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}
在这个例子中:
Observer 接口定义了 update() 方法,所有具体的观察者都需要实现这个方法。
Subject 接口定义了注册、移除和通知观察者的方法。
WeatherData 类实现了 Subject 接口,并在数据变化时通知所有注册的观察者。
CurrentConditionsDisplay 类实现了 Observer 接口,当接收到通知时更新自身的数据显示。
通过这种方式,我们可以轻松地添加更多的观察者(如统计显示器、预测显示器等),而无需修改 WeatherData 类或现有的观察者逻辑,体现了观察者模式的强大灵活性和扩展性。
3-3.应用场景
观察者模式适用于以下情况:
当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这两者封装在独立的对象中使它们可以各自独立地改变和复用。
当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变时。
当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换句话说,你不希望这些对象是紧密耦合的。
例如:
事件处理系统:如图形用户界面中的按钮点击事件、窗口关闭事件等。
订阅发布系统:比如新闻网站上的文章发布后,所有订阅该类文章的用户都能立即收到通知。
状态监控系统:例如服务器健康状况监控,一旦检测到异常,通知相关的监控模块进行处理。