Java中的设计模式在代码重构中的应用-程序员宅基地

技术标签: java  重构  设计模式  

设计模式是在软件开发中经常使用的一种经验总结,用于解决在特定上下文中重复出现的问题。在代码重构中,设计模式可以帮助我们改善代码的结构、可读性和可维护性。
下面是几个常见的设计模式及其在代码重构中的应用。

1. 单例模式(Singleton Pattern)

单例模式确保一个类仅有一个实例,并提供一个全局访问点。在重构中,如果某个类需要频繁创建和销毁对象,但又不希望存在多个实例,可以考虑使用单例模式。

重构前

public class Singleton {
    
    public static Singleton instance;

    public Singleton() {
    }

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

重构后(线程安全):

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;
    }
}

2. 工厂模式(Factory Pattern)

工厂模式用于创建对象,而无需指定创建对象的具体类。它隐藏了实例化对象的逻辑,使得代码更加灵活和易于维护。

重构前

public class Car {
    
    public Car() {
    
        System.out.println("Creating a car...");
    }
}

public class Client {
    
    public static void main(String[] args) {
    
        Car car = new Car();
    }
}

重构后

public interface Car {
    
    void drive();
}

public class SportsCar implements Car {
    
    @Override
    public void drive() {
    
        System.out.println("Driving a sports car...");
    }
}

public class SedanCar implements Car {
    
    @Override
    public void drive() {
    
        System.out.println("Driving a sedan car...");
    }
}

public class CarFactory {
    
    public static Car createCar(String type) {
    
        if ("sports".equalsIgnoreCase(type)) {
    
            return new SportsCar();
        } else if ("sedan".equalsIgnoreCase(type)) {
    
            return new SedanCar();
        } else {
    
            throw new IllegalArgumentException("Invalid car type: " + type);
        }
    }
}

public class Client {
    
    public static void main(String[] args) {
    
        Car sportsCar = CarFactory.createCar("sports");
        sportsCar.drive();
    }
}

3. 观察者模式(Observer Pattern)

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,它的所有依赖者(观察者)都会收到通知并自动更新。

重构前

假设有一个Subject类和一个Observer类,它们直接相互调用。

重构后

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

public interface Observer {
    
    void update(String message);
}

public class ConcreteObserver implements Observer {
    
    @Override
    public void update(String message) {
    
        System.out.println("Received message: " + message);
    }
}

public interface Subject {
    
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers(String message);
}

public class ConcreteSubject implements Subject {
    
    private List<Observer> 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(String message) {
    
        for (Observer observer : observers) {
    
            observer.update(message);
        }
    }
}

public class Client {
    
    public static void main(String[] args) {
    
        ConcreteSubject subject = new ConcreteSubject();
        ConcreteObserver observer = new ConcreteObserver();

        subject.registerObserver(observer);
        subject.notifyObservers("Hello, observers!");
    }
}

这些只是设计模式在代码重构中的几个应用示例。设计模式的种类非常多,每一种模式都有其特定的应用场景和优势。在代码重构过程中,选择适合的设计模式可以帮助我们更好地组织代码,提高代码的可读性、可维护性和可扩展性。

4. 建造者模式(Builder Pattern)

建造者模式用于构建复杂对象,它将对象的构建过程与其表示过程分离,使得同样的构建过程可以创建不同的表示。

重构前

public class Computer {
    
    private String ram;
    private String hdd;
    private String cpu;

    public Computer(String ram, String hdd, String cpu) {
    
        this.ram = ram;
        this.hdd = hdd;
        this.cpu = cpu;
    }

    // getters and setters
}

public class Client {
    
    public static void main(String[] args) {
    
        Computer computer = new Computer("4GB", "500GB", "Intel i5");
    }
}

重构后

public class Computer {
    
    private String ram;
    private String hdd;
    private String cpu;

    // private constructor to prevent direct instantiation
    private Computer(Builder builder) {
    
        this.ram = builder.ram;
        this.hdd = builder.hdd;
        this.cpu = builder.cpu;
    }

    public static class Builder {
    
        private String ram;
        private String hdd;
        private String cpu;

        public Builder setRam(String ram) {
    
            this.ram = ram;
            return this;
        }

        public Builder setHdd(String hdd) {
    
            this.hdd = hdd;
            return this;
        }

        public Builder setCpu(String cpu) {
    
            this.cpu = cpu;
            return this;
        }

        public Computer build() {
    
            return new Computer(this);
        }
    }

    // getters
}

public class Client {
    
    public static void main(String[] args) {
    
        Computer computer = new Computer.Builder()
                .setRam("4GB")
                .setHdd("500GB")
                .setCpu("Intel i5")
                .build();
    }
}

5. 策略模式(Strategy Pattern)

策略模式定义了一系列可以互相替换的算法,使得算法可以独立于使用它的客户端变化。

重构前

假设有一个Sorter类,它根据不同的排序算法直接进行排序。

重构后

public interface SortingStrategy {
    
    void sort(int[] array);
}

public class BubbleSortStrategy implements SortingStrategy {
    
    @Override
    public void sort(int[] array) {
    
        // Bubble sort implementation
    }
}

public class QuickSortStrategy implements SortingStrategy {
    
    @Override
    public void sort(int[] array) {
    
        // Quick sort implementation
    }
}

public class Context {
    
    private SortingStrategy strategy;

    public Context(SortingStrategy strategy) {
    
        this.strategy = strategy;
    }

    public void setSortingStrategy(SortingStrategy strategy) {
    
        this.strategy = strategy;
    }

    public void sort(int[] array) {
    
        strategy.sort(array);
    }
}

public class Client {
    
    public static void main(String[] args) {
    
        Context context = new Context(new BubbleSortStrategy());
        int[] array = {
    5, 3, 8, 4, 2};
        context.sort(array);

        // Change sorting strategy
        context.setSortingStrategy(new QuickSortStrategy());
        context.sort(array);
    }
}

在以上示例中,我们使用了策略模式来将不同的排序算法与它们的使用者(Context类)解耦。这样,我们可以根据需要轻松地更改排序算法,而无需修改使用排序算法的代码。

这些只是设计模式在代码重构中的一些应用示例。在实际项目中,根据具体需求和问题,我们可以选择和应用不同的设计模式来解决复杂性和维护性问题。重要的是理解每种设计模式的原理和适用场景,并在重构过程中灵活应用它们来改进代码的质量和结构。

6. 原型模式(Prototype Pattern)

原型模式是一种创建型设计模式,它允许通过复制一个已存在的对象(原型)来创建新的对象,而不是重新实例化该类。这在创建对象成本较高或需要避免大量重复初始化时非常有用。

重构前

假设有一个复杂的对象ComplexObject,每次创建都需要进行大量的初始化工作。

public class ComplexObject {
    
    private String property1;
    private int property2;
    // ... 其他属性和方法

    public ComplexObject() {
    
        // 复杂的初始化过程
    }
}

public class Client {
    
    public static void main(String[] args) {
    
        ComplexObject obj1 = new ComplexObject();
        ComplexObject obj2 = new ComplexObject();
        // ... 重复创建多个对象
    }
}

重构后

public class ComplexObject implements Cloneable {
    
    private String property1;
    private int property2;
    // ... 其他属性和方法

    // 复制构造函数
    public ComplexObject(ComplexObject prototype) {
    
        this.property1 = prototype.property1;
        this.property2 = prototype.property2;
        // ... 复制其他属性
    }

    @Override
    public ComplexObject clone() {
    
        try {
    
            return new ComplexObject(this);
        } catch (CloneNotSupportedException e) {
    
            throw new Error("This shouldn't happen", e);
        }
    }

    // 其他方法
}

public class Client {
    
    public static void main(String[] args) {
    
        ComplexObject prototype = new ComplexObject();
        // 初始化原型对象

        ComplexObject obj1 = prototype.clone();
        ComplexObject obj2 = prototype.clone();
        // ... 通过克隆原型来创建多个对象
    }
}

7. 模板方法模式(Template Method Pattern)

模板方法模式定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。

重构前

有一个Game类,它包含多个步骤,但某些步骤的具体实现在不同类型的游戏中不同。

重构后

public abstract class Game {
    
    public final void play() {
    
        initializeGame();
        startGame();
        endGame();
    }

    protected abstract void initializeGame();
    protected abstract void startGame();
    protected abstract void endGame();
}

public class FootballGame extends Game {
    
    @Override
    protected void initializeGame() {
    
        // 初始化足球游戏
    }

    @Override
    protected void startGame() {
    
        // 开始足球游戏
    }

    @Override
    protected void endGame() {
    
        // 结束足球游戏
    }
}

public class BasketballGame extends Game {
    
    @Override
    protected void initializeGame() {
    
        // 初始化篮球游戏
    }

    @Override
    protected void startGame() {
    
        // 开始篮球游戏
    }

    @Override
    protected void endGame() {
    
        // 结束篮球游戏
    }
}

public class Client {
    
    public static void main(String[] args) {
    
        Game football = new FootballGame();
        football.play();

        Game basketball = new BasketballGame();
        basketball.play();
    }
}

在这个例子中,Game类定义了游戏的通用流程(play方法),而具体的初始化、开始和结束游戏的步骤则由子类(如FootballGameBasketballGame)来实现。这样,我们可以轻松地添加新的游戏类型,而无需改变游戏的整体结构。

8. 观察者模式(Observer Pattern)

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,它的所有依赖者(观察者)都会自动收到通知并更新。

重构前

当某个对象状态变化时,直接调用其他多个对象的更新方法。

重构后

public interface Observer {
    
    void update(String message);
}

public interface Subject {
    
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
    void setState(String state);
    String getState();
}

public class ConcreteSubject implements Subject {
    
    private List<Observer> observers;
    private String state;

    public ConcreteSubject() {
    
        this.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(state);
        }
    }

    @Override
    public void setState(String state) {
    
        this.state = state;
        notifyObservers();
    }

    @Override
    public String getState() {
    
        return state;
    }
}

public class ConcreteObserver implements Observer {
    
    private String name;
    private String subjectState;

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

    @Override
    public void update(String message) {
    
        subjectState = message;
        display();
    }

    public void display() {
    
        System.out.println(name + " received: " + subjectState);
    }
}

public class Client {
    
    public static void main(String[] args) {
    
        Subject subject = new ConcreteSubject();
        Observer observer1 = new ConcreteObserver("Observer 1");
        Observer observer2 = new ConcreteObserver("Observer 2");

        subject.registerObserver(observer1);
        subject.registerObserver(observer2);

        subject.setState("New state");

        subject.removeObserver(observer1);
        subject.setState("Another state");
    }
}

在这个例子中,Subject是主题,它可以注册、注销观察者,并在状态变化时通知所有注册的观察者。Observer是观察者接口,定义了当主题状态变化时应该执行的操作。ConcreteSubjectConcreteObserver分别是主题和观察者的具体实现。当ConcreteSubject的状态变化时,它会调用notifyObservers方法,该方法会遍历所有注册的观察者并调用它们的update方法。这样,观察者就可以得到主题的最新状态并做出相应处理。

使用观察者模式的好处在于,它降低了主题和观察者之间的耦合度,使得它们可以独立地变化和复用。同时,它也提供了一种灵活的通知机制,使得多个观察者可以同时响应主题状态的变化。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_37638307/article/details/138022955

智能推荐

【数据结构】查找1——线性表的查找(顺序查找、折半查找、分块查找)_图顺序查找-程序员宅基地

文章浏览阅读2.8k次。【数据结构】查找1——线性表的查找(顺序查找、折半查找、分块查找)_图顺序查找

zip包解压时报malformed input off : 0, length : 1-程序员宅基地

文章浏览阅读843次。使用ZipArchiveInputStream而非ZipInputStream的原因主要有以下两点:支持更多的压缩格式:ZipArchiveInputStream是Apache Commons Compress库中提供的类,能够支持多种压缩格式,包括Zip、Gzip、Tar、Jar等。而ZipInputStream是Java标准库中的类,只能读取普通的Zip文件。因此,如果需要处理多种压缩格式的文件,使用ZipArchiveInputStream会更加方便。更多的选项和功能:ZipArchiveInp_malformed input off : 0, length : 1

switch case结合枚举值使用,借助枚举的值来做case分支判断_switch case 枚举-程序员宅基地

文章浏览阅读8.3k次,点赞9次,收藏22次。https://blog.csdn.net/m0_37754981/article/details/80022169参考资料_switch case 枚举

rpc简介及原理-程序员宅基地

文章浏览阅读5.1k次,点赞2次,收藏30次。1.RPC简介及原理介绍RPC技术内部原理是通过两种技术的组合来实现的:本地方法调用 和 网络通信技术。1.1 RPC简介在上述本地过程调用的例子中,我们是在一台计算机上执行了计算机上的程序,完成调用。随着计算机技术的发展和需求场景的变化,有时就需要从一台计算机上执行另外一台计算机上的程序的需求,因此后来又发展出来了RPC技术。特别是目前随着互联网技术的快速迭代和发展,用户和需求几乎都是以指数式的方式在高速增长,这个时候绝大多数情况下程序都是部署在多台机器上,就需要在调用其他物理机器上的程序的情况。_rpc

AI大视觉(十七) | PANet(路径聚合网络)-程序员宅基地

文章浏览阅读7k次,点赞6次,收藏70次。本文来自公众号“AI大道理​目标检测或者实例分割不仅要关心语义信息,还要关注图像的精确到像素点的浅层信息。所以需要对骨干网络中的网络层进行融合,使其同时具有深层的语义信息和浅层的纹理信息。PANet整体结构PANet(Path Aggregation Network)最大的贡献是提出了一个自顶向下和自底向上的双向融合骨干网络,同时在最底层和最高层之间添加了一条“short-cut”,用于缩短层之间的路径。PANet还提出了自适应特征池化和全连接融合两个模块。其中自适应特征_panet

OperationalError: (sqlite3.OperationalError) unable to open database file解决方案_sqlite3.operationalerror: unable to open database -程序员宅基地

文章浏览阅读1.3w次,点赞13次,收藏14次。本文主要介绍了OperationalError: (sqlite3.OperationalError) unable to open database file解决方案,希望能对使用langchain读取sqlite文件的同学们有所帮助。文章目录1. 问题描述2. 解决方案_sqlite3.operationalerror: unable to open database file

随便推点

PID控制详解-程序员宅基地

文章浏览阅读10w+次,点赞551次,收藏3.2k次。PID控制详解一、PID控制简介 PID( Proportional Integral Derivative)控制是最早发展起来的控制策略之一,由于其算法简单、鲁棒性好和可靠性高,被广泛应用于工业过程控制,尤其适用于可建立精确数学模型的确定性控制系统。 在工程实际中,应用最为广泛的调节器控制规律为比例、积分、微分控制,简称PID控制,又称PID调节,它实际上是一种算法。PID控制器问..._pid控制

搭建静态网站-程序员宅基地

文章浏览阅读329次。搭建Http静态服务器环境任务时间:15min ~ 30min搭建静态网站,首先需要部署环境。下面的步骤,将告诉大家如何在服务器上通过 Nginx 部署 HTTP 静态服务。00、安装 Nginx在 CentOS 上,可直接使用yum来安装 Nginxyum install nginx -y安装完成后,使用nginx命令启动 Nginx:n..._在一个目录下创建静态站点

HTML5网页设计 (一)_html5网页制作-程序员宅基地

文章浏览阅读7k次,点赞2次,收藏23次。初始HTML5记事本简单实现HTML5页面_html5网页制作

CentOS 固定IP配置_centos配置ip地址-程序员宅基地

文章浏览阅读6.8k次。1、打开 VMware Workstation,点击 “编辑” -> "虚拟网络编辑器"2、选择 “更改设置”(若界面内没有,则不用理会)3、选择 “VMnet8”,更改为192.168.88.0(按需填写)、为255.255.255.0,点击 “NAT设置”4、更改为192.168.88.2(按需填写),当前界面点击确定,“虚拟网络编辑器”界面再点击确定。_centos配置ip地址

MATLAB 调用 p文件,Matlab中使用.p文件的方法-程序员宅基地

文章浏览阅读2.9k次。首先,P文件为了保护知识产权设计的一种加密文件,是不能查看的。运行比较简单,和调用m文件方法一样。下面是一些解释。P文件是对应M文件的一种预解析版本(preparsedversion)。因为当你第一次执行M文件时,Matlab需要将其解析(parse)一次(第一次执行后的已解析内容会放入内存作第二次执行时使用,即第二次执行时无需再解析),这无形中增加了执行时间。所以我们就预先作解释,那么以后再使用..._matlab怎么调用p文件

[CSS] 内联元素内的文字居中显示(按钮、链接等)_a-button居中-程序员宅基地

文章浏览阅读2.1k次。最近在做一个移动端的响应式页面,对自定义样式要求较高,很多地方需要细微的调整,比如按钮、链接等内联元素,不能只是让它看起来居中,而要做到“响应式”居中……水平居中很简单,但是垂直居中的问题困扰了我很久,直到我研究过bootstrap的_variables.scss文档后,才仔细地了解到一些组件的构造。如果修改了inline/inline-block元素的默认样式后,里面的文字不居中了,试试这个方法,只需要5步~_a-button居中

推荐文章

热门文章

相关标签