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

智能推荐

软件测试流程包括哪些内容?测试方法有哪些?_测试过程管理中包含哪些过程-程序员宅基地

文章浏览阅读2.9k次,点赞8次,收藏14次。测试主要做什么?这完全都体现在测试流程中,同时测试流程是面试问题中出现频率最高的,这不仅是因为测试流程很重要,而是在面试过程中这短短的半小时到一个小时的时间,通过测试流程就可以判断出应聘者是否合适,故在测试流程中包含了测试工作的核心内容,例如需求分析,测试用例的设计,测试执行,缺陷等重要的过程。..._测试过程管理中包含哪些过程

政府数字化政务的人工智能与机器学习应用:如何提高政府工作效率-程序员宅基地

文章浏览阅读870次,点赞16次,收藏19次。1.背景介绍政府数字化政务是指政府利用数字技术、互联网、大数据、人工智能等新技术手段,对政府政务进行数字化改革,提高政府工作效率,提升政府服务质量的过程。随着人工智能(AI)和机器学习(ML)技术的快速发展,政府数字化政务中的人工智能与机器学习应用也逐渐成为政府改革的重要内容。政府数字化政务的人工智能与机器学习应用涉及多个领域,包括政策决策、政府服务、公共安全、社会治理等。在这些领域,人工...

ssm+mysql+微信小程序考研刷题平台_mysql刷题软件-程序员宅基地

文章浏览阅读219次,点赞2次,收藏4次。系统主要的用户为用户、管理员,他们的具体权限如下:用户:用户登录后可以对管理员上传的学习视频进行学习。用户可以选择题型进行练习。用户选择小程序提供的考研科目进行相关训练。用户可以进行水平测试,并且查看相关成绩用户可以进行错题集的整理管理员:管理员登录后可管理个人基本信息管理员登录后可管理个人基本信息管理员可以上传、发布考研的相关例题及其分析,并对题型进行管理管理员可以进行查看、搜索考研题目及错题情况。_mysql刷题软件

根据java代码描绘uml类图_Myeclipse8.5下JAVA代码导成UML类图-程序员宅基地

文章浏览阅读1.4k次。myelipse里有UML1和UML2两种方式,UML2功能更强大,但是两者生成过程差别不大1.建立Test工程,如下图,uml包存放uml类图package com.zz.domain;public class User {private int id;private String name;public int getId() {return id;}public void setId(int..._根据以下java代码画出类图

Flume自定义拦截器-程序员宅基地

文章浏览阅读174次。需求:一个topic包含很多个表信息,需要自动根据json字符串中的字段来写入到hive不同的表对应的路径中。发送到Kafka中的数据原本最外层原本没有pkDay和project,只有data和name。因为担心data里面会空值,所以根同事商量,让他们在最外层添加了project和pkDay字段。pkDay字段用于表的自动分区,proejct和name合起来用于自动拼接hive表的名称为 ..._flume拦截器自定义开发 kafka

java同时输入不同类型数据,Java Spring中同时访问多种不同数据库-程序员宅基地

文章浏览阅读380次。原标题:Java Spring中同时访问多种不同数据库 多样的工作要求,可以使用不同的工作方法,只要能获得结果,就不会徒劳。开发企业应用时我们常常遇到要同时访问多种不同数据库的问题,有时是必须把数据归档到某种数据仓库中,有时是要把数据变更推送到第三方数据库中。使用Spring框架时,使用单一数据库是非常容易的,但如果要同时访问多个数据库的话事件就变得复杂多了。本文以在Spring框架下开发一个Sp..._根据输入的不同连接不同的数据库

随便推点

EFT试验复位案例分析_eft电路图-程序员宅基地

文章浏览阅读3.6k次,点赞9次,收藏25次。本案例描述了晶振屏蔽以及开关电源变压器屏蔽对系统稳定工作的影响, 硬件设计时应考虑。_eft电路图

MR21更改价格_mr21 对于物料 zba89121 存在一个当前或未来标准价格-程序员宅基地

文章浏览阅读1.1k次。对于物料价格的更改,可以采取不同的手段:首先,我们来介绍MR21的方式。 需要说明的是,如果要对某一产品进行价格修改,必须满足的前提条件是: ■ 1、必须对价格生效的物料期间与对应会计期间进行开启; ■ 2、该产品在该物料期间未发生物料移动。执行MR21,例如更改物料1180051689的价格为20000元,系统提示“对于物料1180051689 存在一个当前或未来标准价格”,这是因为已经对该..._mr21 对于物料 zba89121 存在一个当前或未来标准价格

联想启天m420刷bios_联想启天M420台式机怎么装win7系统(完美解决usb)-程序员宅基地

文章浏览阅读7.4k次,点赞3次,收藏13次。[文章导读]联想启天M420是一款商用台式电脑,预装的是win10系统,用户还是喜欢win7系统,该台式机采用的intel 8代i5 8500CPU,在安装安装win7时有很多问题,在安装win7时要在BIOS中“关闭安全启动”和“开启兼容模式”,并且安装过程中usb不能使用,要采用联想win7新机型安装,且默认采用的uefi+gpt模式,要改成legacy+mbr引导,那么联想启天M420台式电..._启天m420刷bios

冗余数据一致性,到底如何保证?-程序员宅基地

文章浏览阅读2.7k次,点赞2次,收藏9次。一,为什么要冗余数据互联网数据量很大的业务场景,往往数据库需要进行水平切分来降低单库数据量。水平切分会有一个patition key,通过patition key的查询能..._保证冗余性

java 打包插件-程序员宅基地

文章浏览阅读88次。是时候闭环Java应用了 原创 2016-08-16 张开涛 你曾经因为部署/上线而痛苦吗?你曾经因为要去运维那改配置而烦恼吗?在我接触过的一些部署/上线方式中,曾碰到过以下一些问题:1、程序代码和依赖都是人工上传到服务器,不是通过工具进行部署和发布;2、目录结构没有规范,jar启动时通过-classpath任意指定;3、fat jar,把程序代码、配置文件和依赖jar都打包到一个jar中,改配置..._那么需要把上面的defaultjavatyperesolver类打包到插件中

VS2015,Microsoft Visual Studio 2005,SourceInsight4.0使用经验,Visual AssistX番茄助手的安装与基本使用9_番茄助手颜色-程序员宅基地

文章浏览阅读909次。1.得下载一个番茄插件,按alt+g才可以有函数跳转功能。2.不安装番茄插件,按F12也可以有跳转功能。3.进公司的VS工程是D:\sync\build\win路径,.sln才是打开工程的方式,一个是VS2005打开的,一个是VS2013打开的。4.公司库里的线程接口,在CmThreadManager.h 里,这个里面是我们的线程库,可以直接拿来用。CreateUserTaskThre..._番茄助手颜色

推荐文章

热门文章

相关标签