1. 程式人生 > 實用技巧 >軟體工程Test1專案總結

軟體工程Test1專案總結

1.主要功能

在正確輸入所需資訊的前提下,本程式提供某地區地鐵路線的線路詳情與最短線路查詢功能

2.實現語言

JAVA

3.實現演算法

主要演算法為Dijkstra演算法

4.類職責劃分(將相關類的功能進行描述)

本程式大致劃分為3部分:UI類,封裝類,控制類(資料生成類)

1).UI類

提供使用者介面:包括歡迎介面(功能選擇),線路查詢介面,線路詳情介面,提示視窗等

線路查詢介面下,使用者輸入起始站與終點站,開始查詢後,若系統沒有檢測到起始站或終點站,則彈出提示框;查詢完成後,在結果視窗輸出所求線路

線路詳情介面下,使用者選擇某一條線路,查詢完成後,在結果視窗輸出該線路下的所有站點

2).封裝類

包括地鐵站點類(節點),地鐵線路類(邊),權重圖構造類等

原始資訊會經過資料構造後存放到相應的封裝類

3).控制類

包含處理演算法,對權重圖進行初始化與計算

計算任意兩個站點間的最短路徑並按一定格式輸出

5.核心程式碼(將所有類的程式碼標註並提交)

控制部分:

DataBuilder類

public class DataBuilder /*throws IOException*/{

    public static Set<List<Station>> lineSet = new HashSet<List<Station>>();//所有線集合
    public
static List<Line> AllLine = new ArrayList<Line>();//所有線集合 public static Map<String, List<Station>> map = new HashMap<String, List<Station>>(); public static List<Station> mapOfStation = new ArrayList<Station>();//存放所有站點 public static int totalStaion = 0;//
總的站點數量 public static void setStations(List<Station> linemodel, String str) { String line=str; String[] line1Arr = line.split(" "); int flag=0; String linename = null; Line newline=new Line(); for(String s : line1Arr){ if(flag==0){ linename=s; newline.setName(linename); } else{ Station station=new Station(s); for(List<Station> lineP : DataBuilder.lineSet){ if(lineP.contains(station)){ DataBuilder.totalStaion -=1;//在其他線路出現過就減1站,不然會重複計算 break; } } mapOfStation.add(station); station.setLinename(linename); linemodel.add(station); } flag=1; } for(int i =0;i<linemodel.size();i++){ if(i<linemodel.size()-1){ linemodel.get(i).next = linemodel.get(i+1); linemodel.get(i+1).prev = linemodel.get(i); } } newline.setStations(linemodel); AllLine.add(newline); map.put(linename,linemodel); } static { for(int i=0;i<Subway.lines.size();i++){ List<Station> line = new ArrayList<Station>(); setStations(line,Subway.lines.get(i)); totalStaion += line.size(); lineSet.add(line); } } }

Subway類

public class Subway {
    public static List<String> lines = new ArrayList<>();//存放所有的線路
    public static List<String> route = new ArrayList<>();
    private List<Station> outList = new ArrayList<Station>();//記錄已經分析過的站點
    
    public void calculate(Station s1, Station s2){//計算從s1站到s2站的最短經過路徑
        String line="初始線";
        if(outList.size() == DataBuilder.totalStaion){
            route.add("找到目標站點:"+s2.getName()+",共經過"+(s1.getAllPassedStations(s2).size()-1)+"站\n");
            int flag=0;
            for(Station station : s1.getAllPassedStations(s2)){
                if(station.getLinename()==null){//出發站
                    route.add(station.getName()+"->");
                }
                else if(station.getName().equals(s2.getName())){//最後1站
                    if(!station.getLinename().equals(line)){
                        route.add("換乘 "+station.getLinename()+"->"+"到達 "+station.getName());
                    }
                    else {
                        route.add("到達 "+station.getName());
                    }
                }
                else if(!station.getLinename().equals(line)&&flag==1){//換乘後1站
                    line=station.getLinename();
                    route.add("換乘"+station.getLinename()+"->"+station.getName()+"->");
                }
                else if(!station.getLinename().equals(line)&&flag==0){//第2站
                    line=station.getLinename();
                    route.add("乘坐"+station.getLinename()+"->"+station.getName()+"->");
                    flag=1;
                }
                else{//其餘站
                    line=station.getLinename();
                    route.add(station.getName()+"->");
                }
            }
            return;
        }
        if(!outList.contains(s1))
            outList.add(s1);
        //如果起點站的OrderSetMap為空,則第一次用起點站的前後站點初始化之
        if(s1.getOrderSetMap().isEmpty()){
            List<Station> Linkedstations = getAllLinkedStations(s1);
            for(Station s : Linkedstations){
                s1.getAllPassedStations(s).add(s);
            }
        }
        Station parent = getShortestPath(s1);//獲取距離起點站s1最近的一個站(有多個的話,隨意取一個)
        if(parent == s2){
            System.out.println("找到目標站點:"+s2+",共經過"+(s1.getAllPassedStations(s2).size()-1)+"站");
            for(Station station : s1.getAllPassedStations(s2)){
                System.out.print(station.getName()+"->");
            }
            return;
        }
        for(Station child : getAllLinkedStations(parent)){
            if(outList.contains(child)){
                continue;
            }
            int shortestPath = (s1.getAllPassedStations(parent).size()-1) + 1;//前面這個1表示計算路徑需要去除自身站點,後面這個1表示增加了1站距離
            if(s1.getAllPassedStations(child).contains(child)){
                //如果s1已經計算過到此child的經過距離,那麼比較出最小的距離
                if((s1.getAllPassedStations(child).size()-1) > shortestPath){
                    //重置S1到周圍各站的最小路徑
                    s1.getAllPassedStations(child).clear();
                    s1.getAllPassedStations(child).addAll(s1.getAllPassedStations(parent));
                    s1.getAllPassedStations(child).add(child);
                }
            } else {
                //如果s1還沒有計算過到此child的經過距離
                s1.getAllPassedStations(child).addAll(s1.getAllPassedStations(parent));
                s1.getAllPassedStations(child).add(child);
            }
        }
        outList.add(parent);
        calculate(s1,s2);//重複計算,往外面站點擴充套件
    }
    private Station getShortestPath(Station station){//獲取引數station到各個站的最短距離,相隔1站,距離為1,依次類推
        int minPatn = Integer.MAX_VALUE;
        Station rets = null;
        for(Station s :station.getOrderSetMap().keySet()){
            if(outList.contains(s)){
                continue;
            }
            LinkedHashSet<Station> set  = station.getAllPassedStations(s);//引數station到s所經過的所有站點的集合
            if(set.size() < minPatn){
                minPatn = set.size();
                rets = s;
            }
        }
        return rets;
    }
    private List<Station> getAllLinkedStations(Station station){//獲取引數station直接相連的所有站,包括交叉線上面的站
        List<Station> linkedStaions = new ArrayList<Station>();
        for(List<Station> line : DataBuilder.lineSet){
            if(line.contains(station)){//如果某一條線包含了此站,注意由於重寫了hashcode方法,只有name相同,即認為是同一個物件
                Station s = line.get(line.indexOf(station));
                if(s.prev != null){
                    linkedStaions.add(s.prev);
                }
                if(s.next != null){
                    linkedStaions.add(s.next);
                }
            }
        }
        return linkedStaions;
    }
}

UI部分:

FrmQueryLine類

public class FrmQueryLine extends JDialog implements ActionListener {
    private JPanel toolBar = new JPanel();
    private JPanel workPane = new JPanel();
    private JButton btnOk = new JButton("查詢");
    private JLabel labelLineName = new JLabel("請輸入線路名稱:");
    private JTextArea lineinformation=new JTextArea();

    List<String> list=new Line().loadAllLineName();
    String[] ingName = list.toArray(new String[list.size()]);
    private JComboBox cmbIngredient= new JComboBox(ingName);

    public FrmQueryLine(Frame f, String s, boolean b) {
        super(f, s, b);
        workPane.setLayout(null);
        labelLineName.setBounds(10, 9, 129, 19);
        workPane.add(labelLineName);
        cmbIngredient.setBounds(146, 7, 96, 23);
        workPane.add(cmbIngredient);
        btnOk.setBounds(268, 5, 75, 23);
        workPane.add(btnOk);
        lineinformation.setFont(new Font("Monospaced", Font.BOLD, 14));
        lineinformation.setLineWrap(true);//啟用自動換行功能
        lineinformation.setWrapStyleWord(false);//啟用斷行不斷字功能
        lineinformation.setBounds(22, 54, 643, 167);
        workPane.add(lineinformation);
        this.getContentPane().add(workPane, BorderLayout.CENTER);
        this.setSize(700, 300);
        //螢幕居中顯示
        double width = Toolkit.getDefaultToolkit().getScreenSize().getWidth();
        double height = Toolkit.getDefaultToolkit().getScreenSize().getHeight();
        this.setLocation((int) (width - this.getWidth()) / 2,
                (int) (height - this.getHeight()) / 2);

        this.validate();
        this.btnOk.addActionListener(this);

    }
    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource()==this.btnOk){
            String ingredientName=this.cmbIngredient.getSelectedItem().toString();
            try {
                List<Station> stations=DataBuilder.map.get(ingredientName);
                lineinformation.setText("");
                for(int i=0;i<stations.size();i++) {
                    Station station=stations.get(i);
                    if(i==stations.size()-1)
                        lineinformation.append(station.getName());
                    else
                        lineinformation.append(station.getName()+"<->");
                }
                lineinformation.paintImmediately(lineinformation.getBounds());
            } catch (Exception e1) {
                JOptionPane.showMessageDialog(null, e1.getMessage(), "錯誤",JOptionPane.ERROR_MESSAGE);
                return;
            }
        }
    }
}

FrmQueryRoute類

public class FrmQueryRoute extends JDialog implements ActionListener {
    private JPanel toolBar = new JPanel();
    private JPanel workPane = new JPanel();
    private JButton btnOk = new JButton("查詢");
    private JLabel labelS1 = new JLabel("起始站:");
    private JLabel labelS2 = new JLabel("目標站:");
    private JTextArea lineinformation=new JTextArea();

    private JTextField edtS1 = new JTextField(20);
    private JTextField edtS2 = new JTextField(20);

    public FrmQueryRoute(Frame f, String s, boolean b) {
        super(f, s, b);
        workPane.setLayout(null);
        labelS1.setBounds(26, 9, 67, 15);
        workPane.add(labelS1);
        edtS1.setBounds(103, 6, 126, 21);
        workPane.add(edtS1);
        labelS2.setBounds(265, 9, 67, 15);
        workPane.add(labelS2);
        edtS2.setBounds(361, 6, 126, 21);
        workPane.add(edtS2);
        btnOk.setBounds(519, 5, 77, 23);
        workPane.add(btnOk);
        lineinformation.setFont(new Font("Monospaced", Font.BOLD, 14));
        lineinformation.setLineWrap(true);//啟用自動換行功能
        lineinformation.setWrapStyleWord(false);//啟用斷行不斷字功能
        lineinformation.setBounds(36, 33, 908, 204);
        workPane.add(lineinformation);
        this.getContentPane().add(workPane, BorderLayout.CENTER);
        this.setSize(1000, 300);
        // 螢幕居中顯示
        double width = Toolkit.getDefaultToolkit().getScreenSize().getWidth();
        double height = Toolkit.getDefaultToolkit().getScreenSize().getHeight();
        this.setLocation((int) (width - this.getWidth()) / 2,
                (int) (height - this.getHeight()) / 2);

        this.validate();
        this.btnOk.addActionListener(this);

    }
    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource()==this.btnOk){
            String S1Name=this.edtS1.getText();
            String S2Name=this.edtS2.getText();
            try {
                int flag1=0,flag2=0;
                for(Station s:DataBuilder.mapOfStation) {
                    if(S1Name.equals(s.getName())) {
                        flag1=1;
                    }
                    if(S2Name.equals(s.getName())) {
                        flag2=1;
                    }
                }
                if(flag1==0) throw new Exception("起始站不存在");
                if(flag2==0) throw new Exception("目標站不存在");
                lineinformation.setText("");//清空JTextArea
                if(S1Name.equals(S2Name))
                    lineinformation.append("目的站與起始站相同");
                else {
                    Subway sw = new Subway();
                    Subway.route.clear();//再次執行清空路線
                    sw.calculate(new Station(S1Name), new Station(S2Name));
                    for(String str:Subway.route)
                        lineinformation.append(str);
                }
                lineinformation.paintImmediately(lineinformation.getBounds());
            } catch (Exception e1) {
                JOptionPane.showMessageDialog(null, e1.getMessage(), "錯誤",JOptionPane.ERROR_MESSAGE);
                return;
            }
        }
    }
}

6.測試用例(將輸入輸出結果截圖提交)

7.總結

部分抄襲程式碼:https://blog.csdn.net/wangchsh2008/article/details/46288967

感謝UI指導!

git:https://github.com/Non-Exited/31701056/tree/master/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B