软件设计(实验三):经典软件体系结构风格(二)

实验目的: 

本实验旨在帮助学生理解和实现两种常见的软件体系结构风格:事件的隐式调用软件体系结构、层次软件体系结构。通过编写具体的代码,学生将能够掌握这两种风格的基本原理,并能够评估它们在不同场景下的适用性和优劣。

基于层次软件体系结构设计如下软件。

图2 用户图形界面

第一层:

为用户图形界面层:包括:JFrame、JPanel、JLabel、JTextArea、JComboBox

JComboBox中可选插入排序、冒泡排序;如上图2所示:

第二层:

为测试案例层,包括软件测试工程师所编写的测试案例:生成随机数、执行排序操作、获取运行时间;

第三层:

被测试软件层(排序算法)。

                            

实验要求:

1. 调试基于事件处理的隐式调用风格实例,并分析隐式调用的程序结构及事件处理过程。

2. 设计并实现基于层次结构的排序算法实例,在插入排序、冒泡排序的基础上,增加归并排序与快速排序;随机生成20个整数,在输出区域显示排序结果及运行时间。

代码:

第一层:

关于SwingUtilities.invokeLater:

SwingUtilities.invokeLater(Runnable doRun) 是 Java Swing 图形用户界面(GUI)工具包中的一个非常重要的方法。它用于在事件调度线程(Event Dispatching Thread,简称 EDT)上安排执行一个 Runnable 任务。EDT 是 Swing 框架中用于处理所有事件(如按键、鼠标点击等)和用户界面更新的线程。

在 Swing 应用程序中,所有与 GUI 相关的更新都应该在 EDT 上执行,以确保线程安全和界面的响应性。如果尝试从其他线程(即非 EDT 线程)更新 Swing 组件,可能会导致不可预测的行为,比如界面冻结、不更新或者抛出异常。

SwingUtilities.invokeLater(Runnable doRun) 方法的参数是一个实现了 Runnable 接口的对象,该接口定义了一个 run() 方法,其中包含了你希望在 EDT 上执行的代码。当你调用 invokeLater 方法时,你传递的 Runnable 对象(即包含了你想要在 EDT 上执行的代码的 run() 方法)会被排队,并尽快在 EDT 上执行,但不会立即执行,因为 EDT 可能正在处理其他事件。

为什么通常推荐使用SwingUtilities.invokeLater的原因:

  1. 线程安全:Swing组件不是线程安全的。如果你从非EDT线程直接访问或修改Swing组件,可能会导致不可预测的行为,如界面更新不一致、组件不响应事件或抛出异常。

  2. 响应性:EDT负责处理所有的事件(如鼠标点击、键盘输入等)和界面更新。如果GUI的创建和初始化过程在主线程中执行,并且这些操作耗时较长,那么界面可能会在这段时间内无响应。

  3. 最佳实践:遵循Swing的最佳实践可以使你的代码更加健壮、可维护和可移植。

  4. 避免潜在的bug:即使你的应用程序在开发过程中没有表现出问题,但在不同的环境或配置下,不使用SwingUtilities.invokeLater可能会导致难以追踪的bug。

在你的例子中,如果SortingApp是一个继承自JFrame或包含Swing组件的类,并且setVisible(true)是用来显示窗口的,那么最好使用SwingUtilities.invokeLater来确保这一操作在EDT上执行。

如果你确定SortingApp的构造和setVisible(true)调用不会涉及任何耗时的操作,并且你的应用程序的其余部分(如果有的话)不会与GUI的创建和显示发生冲突,那么从技术上讲,你可以不使用SwingUtilities.invokeLater。然而,为了保持代码的健壮性和遵循Swing的最佳实践,建议始终使用它。

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class SortingApp extends JFrame {
    private JComboBox<String> sortOptions;
    private JTextArea resultArea, inputArea;

    public SortingApp() {
        setTitle("排序演示");
        setSize(400, 300);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        JPanel inputPanel = new JPanel();
//        panel.setLayout(new BorderLayout());

        panel.setLayout(new FlowLayout());
        String[] options = {"插入排序", "冒泡排序"};
        sortOptions = new JComboBox<>(options);
        JButton sortButton = new JButton("排序");
        resultArea = new JTextArea(3, 30);
        inputArea = new JTextArea(10, 30);
//自动换行
        inputArea.setLineWrap(true);
        inputArea.setWrapStyleWord(true);
        resultArea.setEditable(false);
        inputArea.setEditable(false);

        sortButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String selected = (String) sortOptions.getSelectedItem();
                SortTester tester = new SortTester();
                String result = "";
                if ("插入排序".equals(selected)) {
                    result = tester.testInsertionSort();
                } else if ("冒泡排序".equals(selected)) {
                    result = tester.testBubbleSort();
                }
                resultArea.setText(result);
//将arry转成带分隔符的字符串 能够在testarea中输出
                int[] array = tester.array; // 假设tester.array已经被正确定义和初始化
                String separator = ", ";
// 首先,将int[]转换为String[]
                String[] stringArray = new String[array.length];
                for (int i = 0; i < array.length; i++) {
                    stringArray[i] = String.valueOf(array[i]);
                }
// 然后,使用String.join()方法将String[]转换为一个字符串
                String resultArray = String.join(separator, stringArray);

                System.out.println(resultArray); // 输出类似: "1, 2, 3, ..."
                inputArea.setText(selected.toString()+":\n"+resultArray);
            }
        });

        panel.add(sortOptions);
        panel.add(sortButton);
        panel.add(resultArea);
        panel.add(new JScrollPane(inputArea));
        add(panel);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            SortingApp app = new SortingApp();
            app.setVisible(true);
        });
    }
}

第二层:

import java.util.Random;

public class SortTester {
    private static final int ARRAY_SIZE = 100;

    public String testInsertionSort() {
        int[] array = generateRandomArray(ARRAY_SIZE);
        long startTime = System.nanoTime();
        SortImp sortImp = new SortImp();
        sortImp.insertionSort(array);
        long endTime = System.nanoTime();

        return "插入排序完成。耗时:" + (endTime - startTime) + " 纳秒";
    }

    public String testBubbleSort() {
        int[] array = generateRandomArray(ARRAY_SIZE);
        long startTime = System.nanoTime();
        SortImp sortImp = new SortImp();
        sortImp.bubbleSort(array);
        long endTime = System.nanoTime();

        return "冒泡排序完成。耗时:" + (endTime - startTime) + " 纳秒";
    }

    private int[] generateRandomArray(int size) {
        Random rand = new Random();
        int[] array = new int[size];
        for (int i = 0; i < size; i++) {
            array[i] = rand.nextInt(1000);
        }
        return array;
    }


}

第三层:

public class SortImp {
    // 插入排序实现
    public void insertionSort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            int key = array[i];
            int j = i - 1;
            while (j >= 0 && array[j] > key) {
                array[j + 1] = array[j];
                j = j - 1;
            }
            array[j + 1] = key;
        }
    }

    // 冒泡排序实现
    public void bubbleSort(int[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            for (int j = 0; j < array.length - i - 1; j++) {
                if (array[j] > array[j + 1]) {
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
        }
    }
}

结果:

猜你喜欢

转载自blog.csdn.net/m0_61338837/article/details/142513145