在项目中应用设计模式的实践指南

目录

✨✨ 祝屏幕前的您天天开心,每天都有好运相伴。我们一起加油!✨✨
🎈🎈作者主页: 喔的嘛呀🎈🎈

引言

一. 单例模式(Singleton Pattern)

1、实现单例模式的方式

1.1 懒汉式(Lazy Initialization)

1.2. 饿汉式(Eager Initialization)

1.3. 双重检查锁(Double-Checked Locking)

2、在项目中的应用

3、总结

二、 工厂模式(Factory Pattern)

1、工厂模式的实现方式

1.1简单工厂模式(Simple Factory Pattern)

1.2、工厂方法模式(Factory Method Pattern)

2、工厂模式在项目中的应用

3、总结

三. 观察者模式(Observer Pattern)

观察者模式的角色

观察者模式的优点

观察者模式的应用场景

示例代码

总结

四. 策略模式(Strategy Pattern)

策略模式的角色

策略模式的优点

策略模式的应用场景

示例代码

总结

结论


引言

设计模式是软件开发中的重要概念,它提供了一套经过验证的解决方案,可以帮助我们解决常见的设计问题。在项目中合理应用设计模式可以提高代码的质量和可维护性。本文将详细介绍如何在项目中应用设计模式,并提供具体的示例代码来说明。

一. 单例模式(Singleton Pattern)

单例模式用于确保一个类只有一个实例,并提供一个全局访问点。在项目中,单例模式通常用于管理共享资源或全局配置。

单例模式(Singleton Pattern)是一种创建型设计模式,用于确保一个类只有一个实例,并提供一个全局访问点。这种模式非常有用,特别是当一个类需要被多个不同的部分使用时,但我们希望这个类的实例始终保持一致性时。

1、实现单例模式的方式

1.1 懒汉式(Lazy Initialization)

在第一次被调用时才创建实例。

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
1.2. 饿汉式(Eager Initialization)

在类加载时就创建实例。

public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}
1.3. 双重检查锁(Double-Checked Locking)

结合懒汉式和同步锁,在保证线程安全的同时减少同步开销。

public class Singleton {
    private volatile static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

2、在项目中的应用

在项目中,单例模式经常被用于以下情况:

  1. 日志记录器(Logger):一个应用可能需要一个全局的日志记录器来记录应用中的事件和错误信息。单例模式可以确保所有部分都使用相同的日志记录器实例。

  2. 配置管理器(Configuration Manager):一个应用可能需要一个全局的配置管理器来加载和保存配置信息。单例模式可以确保所有部分都使用相同的配置管理器实例。

  3. 数据库连接池(Database Connection Pool):在需要频繁访问数据库的应用中,可以使用单例模式管理数据库连接池,以避免频繁地创建和销毁连接。

  4. 线程池(Thread Pool):在需要管理多个线程的应用中,可以使用单例模式管理线程池,以便统一管理线程的创建和销毁。

  5. 缓存管理器(Cache Manager):在需要缓存数据的应用中,可以使用单例模式管理缓存,以便统一管理缓存的读写操作。

  6. GUI组件管理器(GUI Component Manager):在需要管理用户界面组件的应用中,可以使用单例模式管理界面组件,以确保所有部分都使用相同的界面组件实例。

以上是单例模式在项目中的一些常见应用场景。在实际项目中,可以根据具体需求和场景来灵活应用单例模式,以提高代码的质量和可维护性。

3、总结

单例模式是一种简单但非常有用的设计模式,在项目中经常被使用。然而,需要注意在多线程环境下保证线程安全,以及避免对单例实例进行破坏性操作(如反序列化)。

二、 工厂模式(Factory Pattern)

工厂模式是一种创建型设计模式,用于创建对象,但将对象的创建逻辑封装在工厂类中,从而实现解耦。工厂模式可以根据不同的条件来创建不同类型的对象,而客户端代码只需要知道如何使用工厂类来获取对象,而不需要知道具体对象的创建细节。

1、工厂模式的实现方式

1.1简单工厂模式(Simple Factory Pattern)

public interface Shape {
    void draw();
}

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个圆形");
    }
}

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个矩形");
    }
}

public class ShapeFactory {
    public Shape getShape(String shapeType) {
        if (shapeType == null) {
            return null;
        }
        if (shapeType.equalsIgnoreCase("circle")) {
            return new Circle();
        } else if (shapeType.equalsIgnoreCase("rectangle")) {
            return new Rectangle();
        }
        return null;
    }
}

1.2、工厂方法模式(Factory Method Pattern)

public interface Shape {
    void draw();
}

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个圆形");
    }
}

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个矩形");
    }
}

public interface ShapeFactory {
    Shape createShape();
}

public class CircleFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Circle();
    }
}

public class RectangleFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Rectangle();
    }
}

2、工厂模式在项目中的应用

工厂模式在项目中的应用非常广泛,它主要用于创建对象,但将对象的创建逻辑封装在工厂类中,从而实现解耦。以下是工厂模式在项目中常见的应用场景和示例:

  1. 数据库连接工厂:在需要访问数据库的应用中,可以使用数据库连接工厂来创建数据库连接对象,根据不同的数据库类型返回不同的连接对象。
public interface Connection {
    void connect();
}

public class MySqlConnection implements Connection {
    @Override
    public void connect() {
        System.out.println("连接到MySQL数据库");
    }
}

public class OracleConnection implements Connection {
    @Override
    public void connect() {
        System.out.println("连接到Oracle数据库");
    }
}

public class ConnectionFactory {
    public static Connection getConnection(String dbType) {
        if ("mysql".equalsIgnoreCase(dbType)) {
            return new MySqlConnection();
        } else if ("oracle".equalsIgnoreCase(dbType)) {
            return new OracleConnection();
        }
        return null;
    }
}

日志记录器工厂:在需要记录日志的应用中,可以使用日志记录器工厂来创建日志记录器对象,根据不同的日志级别返回不同的日志记录器对象。

public interface Logger {
    void log(String message);
}

public class InfoLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("[INFO] " + message);
    }
}

public class ErrorLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("[ERROR] " + message);
    }
}

public class LoggerFactory {
    public static Logger getLogger(String logLevel) {
        if ("info".equalsIgnoreCase(logLevel)) {
            return new InfoLogger();
        } else if ("error".equalsIgnoreCase(logLevel)) {
            return new ErrorLogger();
        }
        return null;
    }
}

文件解析器工厂:在需要解析不同类型文件的应用中,可以使用文件解析器工厂来创建文件解析器对象,根据不同的文件类型返回不同的解析器对象。

public interface Parser {
    void parse(String filePath);
}

public class XmlParser implements Parser {
    @Override
    public void parse(String filePath) {
        System.out.println("解析XML文件:" + filePath);
    }
}

public class JsonParser implements Parser {
    @Override
    public void parse(String filePath) {
        System.out.println("解析JSON文件:" + filePath);
    }
}

public class ParserFactory {
    public static Parser getParser(String fileType) {
        if ("xml".equalsIgnoreCase(fileType)) {
            return new XmlParser();
        } else if ("json".equalsIgnoreCase(fileType)) {
            return new JsonParser();
        }
        return null;
    }
}

3、总结

工厂模式可以帮助我们在项目中实现对象的创建和管理,同时降低了类之间的耦合度,使得代码更加灵活和可维护。在实际项目中,根据具体需求和场景,可以灵活应用工厂模式来提高代码的质量和可扩展性。

三. 观察者模式(Observer Pattern)

观察者模式是一种行为设计模式,用于定义对象间的一对多依赖关系,当一个对象状态发生改变时,所有依赖于它的对象都会收到通知并自动更新。这种模式涉及到两种类型的对象:主题(Subject)和观察者(Observer)。主题维护一组观察者,提供注册和删除观察者的方法,并在状态变化时通知观察者。

观察者模式的角色

  1. Subject(主题):被观察的对象,它维护一组观察者,并提供注册和删除观察者的方法,以及通知观察者的方法。
  2. ConcreteSubject(具体主题):实现主题接口的具体对象,它存储主题的状态,当状态发生变化时通知所有观察者。
  3. Observer(观察者):定义一个更新接口用于接收并响应主题状态的变化。
  4. ConcreteObserver(具体观察者):实现观察者接口的具体对象,当接收到主题通知时执行特定的动作。

观察者模式的优点

  • 松耦合:主题和观察者之间是松耦合的,主题只知道观察者接口,而不需要了解具体的观察者实现。
  • 可扩展性:可以在运行时动态添加新的观察者。
  • 反应性:观察者能够立即对主题的状态变化做出响应。

观察者模式的应用场景

  • 当一个对象的改变需要同时改变其他对象,并且不知道具体有多少对象需要改变时,可以使用观察者模式。
  • 当一个抽象模型有两个方面,其中一个依赖于另一个,使用观察者模式可以将这两者封装在独立的对象中,使它们可以独立地改变和复用。

示例代码

以下是一个简单的观察者模式示例,模拟了一个简单的气象站发布天气信息的场景:

import java.util.ArrayList;
import java.util.List;

// 主题接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 观察者接口
interface Observer {
    void update(float temperature, float humidity, float pressure);
}

// 具体主题
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 observer) {
        observers.add(observer);
    }

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

    @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();
    }
}

// 具体观察者
class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;

    @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.registerObserver(currentDisplay);

        weatherData.setMeasurements(80, 65, 30.4f);
    }
}

在这个示例中,WeatherData 是具体主题,Display 是具体观察者。当气象站的温度发生变化时,会通知所有注册的观察者更新温度信息。

总结

观察者模式的优点包括降低耦合度、支持广播通信和扩展性好。在项目中,观察者模式常用于事件处理、消息通知和状态监控等场景。通过观察者模式,可以使系统的各个部分之间保持松散耦合,提高代码的灵活性和可维护性。

四. 策略模式(Strategy Pattern)

策略模式是一种行为设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式可以让算法独立于使用它的客户端而变化,即客户端可以根据需要在运行时选择算法。在项目中,策略模式可以用于实现不同的算法或行为,使系统更灵活、可扩展和易于维护。

策略模式的角色

  1. Context(上下文):维护一个对策略对象的引用,在需要的时候调用策略对象的算法。
  2. Strategy(策略):定义所有支持的算法的公共接口,通常是一个接口或抽象类。
  3. ConcreteStrategy(具体策略):实现策略接口,提供具体的算法实现。

策略模式的优点

  • 算法独立性:可以在不影响客户端的情况下单独修改或替换算法。
  • 扩展性:易于增加新的算法或行为。
  • 复用性:可以将算法封装成独立的策略类,方便复用。

策略模式的应用场景

  • 当一个系统中有许多类只是在行为上有差别,可以使用策略模式来将这些行为封装到不同的策略类中,使得这些类可以方便地切换行为。
  • 当一个类的某个行为需要在运行时动态地选择时,可以使用策略模式。

示例代码

以下是一个简单的策略模式示例,模拟了一个电商系统根据不同的促销策略计算折扣价格的场景:

// 策略接口
interface DiscountStrategy {
    double applyDiscount(double amount);
}

// 具体策略:打折策略
class PercentageDiscountStrategy implements DiscountStrategy {
    private double percentage;

    public PercentageDiscountStrategy(double percentage) {
        this.percentage = percentage;
    }

    @Override
    public double applyDiscount(double amount) {
        return amount * (1 - percentage);
    }
}

// 具体策略:满减策略
class FullReductionDiscountStrategy implements DiscountStrategy {
    private double full;
    private double reduction;

    public FullReductionDiscountStrategy(double full, double reduction) {
        this.full = full;
        this.reduction = reduction;
    }

    @Override
    public double applyDiscount(double amount) {
        return amount >= full ? amount - reduction : amount;
    }
}

// 上下文
class ShoppingCart {
    private DiscountStrategy discountStrategy;

    public void setDiscountStrategy(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    public double checkout(double amount) {
        return discountStrategy.applyDiscount(amount);
    }
}

public class StrategyPatternExample {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        // 使用打折策略
        cart.setDiscountStrategy(new PercentageDiscountStrategy(0.1));
        double discountedPrice = cart.checkout(100);
        System.out.println("打折后价格:" + discountedPrice);

        // 使用满减策略
        cart.setDiscountStrategy(new FullReductionDiscountStrategy(200, 50));
        discountedPrice = cart.checkout(250);
        System.out.println("满减后价格:" + discountedPrice);
    }
}

在这个示例中,DiscountStrategy 是策略接口,PercentageDiscountStrategyFullReductionDiscountStrategy 是具体策略。ShoppingCart 类是上下文,根据不同的促销策略计算折扣价格。

总结

总的来说,策略模式可以让算法的变化独立于使用算法的客户端,使得系统更灵活、可扩展和易于维护。

结论

设计模式是软件开发中的重要概念,通过合理应用设计模式,可以提高代码的质量和可维护性。在项目中应用设计模式需要根据具体情况选择合适的模式,并遵循设计模式的原则和规范。希望本文能帮助读者更好地理解和应用设计模式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/406960.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

neo4j创建新数据库

根据网上提供的教程&#xff0c;neo4j并没有提供创建数据库的命令&#xff0c;其只有一个默认数据库graph.db&#xff0c;该数据库中的所有数据将存储在neo4j安装路径下的data/databases/graph.db目录中。 因此&#xff0c;我们猜想&#xff0c;如果我们将默认数据库的名字修改…

【Vue渗透】Vue Devtools 浏览器插件

下载地址 Vue Devtools 浏览器插件 Vue站点渗透思路 【Vue渗透】Vue站点渗透思路 简介 Vue Devtools 是 Vue 官方发布的调试浏览器插件&#xff0c;可以安装在 Chrome 和 Firefox 等浏览器上&#xff0c;直接内嵌在开发者工具中&#xff0c;使用体验流畅。Vue Devtools 由…

【复现】用友U8 oa协同工作系统 文件上传漏洞_57

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 用友U8 &#xff0d;OA 协同办公管理系统&#xff0c;可把日常业务、事物、协作等信息在企业的各分子公司、部门、群组、个人之间…

Nginx网络服务四-----日志、Nginx压缩和ssl

1.自定义访问日志 如果访问出错---404&#xff0c;可以去看error.log日志信息 访问日志是记录客户端即用户的具体请求内容信息&#xff0c;而在全局配置模块中的error_log是记录nginx服务器运行时的日志保存路径和记录日志的level&#xff0c;因此两者是不同的&#xff0c;而且…

Linux——简单的Shell程序

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、Shell程序思路二、Shell代码展示 一、Shell程序思路 用下图的时间轴来表示事件的发生次序…

广联达Linkworks GetAllData 信息泄露漏洞复现

0x01 产品简介 广联达 LinkWorks(也称为 GlinkLink 或 GTP-LinkWorks)是广联达公司(Glodon)开发的一种BIM(建筑信息模型)协同平台。广联达是中国领先的数字建造技术提供商之一,专注于为建筑、工程和建筑设计行业提供数字化解决方案。 0x02 漏洞概述 广联达-Linkworks…

QT常用类

五、常用类 QString 字符串类&#xff08;掌握&#xff09; QString是Qt的字符串类&#xff0c;与C的std::string相比&#xff0c; 不再使用ASCII编码。QString使用的是Unicode编码。 QString中每个字符都是一个16位的QChar&#xff0c;而不是8位的char。 QString完全支持中文&…

2、Web攻防-SQL注入-联合查询注入

用途&#xff1a;个人学习笔记&#xff0c;有所借鉴&#xff0c;欢迎指正&#xff01; 声明&#xff1a;只用于学习交流&#xff0c;点到为止&#xff0c;请勿非法测试。 概念&#xff1a; 联合查询注入&#xff1a;联合注入是回显注入的一种&#xff0c;也就是说联合注入的前…

解决docker中运行的jar包连不上数据库

目录 数据库主机地址设置问题&#xff1a; 网络连接问题&#xff1a; 数据库端口映射&#xff1a; 数据库认证问题&#xff1a; 数据库服务是否正常运行&#xff1a; 日志查看&#xff1a; 如果在 Docker 中运行的 JAR 包无法连接到数据库&#xff0c;有几个可能的原因和…

「JavaSE」String类3:字符串常量池

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;快来卷Java啦 &#x1f387;欢迎点赞收藏加关注哦&#xff01; 字符串常量池 &#x1f349;常量池&#x1f349;字符串常量池&#x1f349;intern 方法 &#x1f349;常量池 在Java程序中&…

Docker 第十九章 : 阿里云个人镜像仓使用

Docker 第十九章 : 阿里云个人镜像仓使用 本章知识点: 如何创建镜像库,如何设置密码,如何登录与退出个人镜像仓,如何本地打镜像,如何将本地镜像推送到个人镜像库。 背景 在项目YapiDocker部署中,因读取mongo:latest 版本不一致,导致后续执行步骤的异常。遇到此场景…

document.cookie中expires 格式设置问题导致部分iphone safari上登录失效

一、问题描述 设备信息&#xff1a;iPhone 12, iOS 16.3 昨天有个小伙伴发现自己的iPhone safari打开网页登录时&#xff0c;登录页面显示登录成功&#xff0c;但实际进入首页后仍然显示未登录。多次测试&#xff0c;该问题在该设备上属于必现问题。 二、问题排查与解决 经过…

AI误导游戏——LLM的危险幻觉

在当今科技高速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;已成为日常生活和工作中不可或缺的一部分。特别是大语言模型&#xff08;LLM&#xff09;如GPT-4等&#xff0c;它们的智能表现令人惊叹&#xff0c;广泛应用于文本生成、语言翻译、情感分析等多个领域…

easyrecovery数据恢复软件14中文绿色版下载

EasyRecovery易恢复14全面介绍 一、功能概览 EasyRecovery易恢复14是一款功能强大的数据恢复软件&#xff0c;旨在帮助用户从各种存储介质中恢复丢失或删除的文件。无论是由于误删、格式化、系统崩溃还是其他未知原因导致的数据丢失&#xff0c;EasyRecovery易恢复14都能提供…

二十九、图像的高斯双边模糊操作

项目功能实现&#xff1a;对一张图片进行高斯双边模糊操作 按照之前的博文结构来&#xff0c;这里就不在赘述了 高斯双边模糊考虑的是图像的x、y方向和RGB方向&#xff0c;两个边 python版本可参考博文&#xff1a;八、边缘保留滤波(EPF) 一、头文件 bilateral_blur.h #pr…

虚 拟 化原理

1 概念&#xff1a; ①通俗理解&#xff1a; 虚拟化是在硬件和操作系统之间的实践 ②通过对计算机的服务层级的理解&#xff0c;理解虚拟化概念 抽离层级之间的依赖关系&#xff08;服务器虚拟化&#xff09; 2 虚拟化分类 ①按架构分类 ◆寄居架构&#xff1a;装在操作系统上…

文件操作知识点(下)

文件操作知识点&#xff08;上&#xff09;-CSDN博客 文件操作知识点(中&#xff09;-CSDN博客 本节继续复习文件操作的相关知识&#xff0c;收尾。 文件读取结束的判定 应该要牢记&#xff0c; 判断文件是否读取结束不要直接使用feof。 feof的作用是&#xff1a;当文件读取…

XSS原理和攻防

Cross Site Scripting:跨站脚本攻击 用户提交的数据中可以构造恶意代码&#xff0c;并且执行&#xff0c;从而实现窃取用户信息等攻击 攻击&#xff1a; 防御&#xff1a; 1.对输入进行过滤&#xff0c;对输出进行编码 2.cookie设置http-only

链表 删除链表中任意位置的节点

//删除链表中任意位置的节点 #include<stdio.h> #include <stdlib.h> struct Node {int data;struct Node* next; }; struct Node* head; void Insert(int x){Node* temp(Node*)malloc(sizeof(struct Node));//创建节点/*malloc返回指向起始地址的指针 因为malloc…

node 之 fs文件系统模块

1.什么是fs文件系统模块 fs模块是Node.js官方提供的、用来操作文件的模块。它提供了一系列的方法和属性&#xff0c;用来满足用户对文件的操作需求 fs.readFile(),用来读取制定文件中的内容 fs.writeFile(),用来向制定的文件中写入内容 如果要在JavaScript代码中&#xff0c;使…