哈工大軟體構造Lab3(2022)

来源:https://www.cnblogs.com/kalesky/archive/2022/08/10/16573431.html
-Advertisement-
Play Games

(防扒小助手) 本人CSDN博客: https://blog.csdn.net/m0_61753302 本人博客園博客(同步CSDN): 何以牽塵 - 博客園 (cnblogs.com)https://www.cnblogs.com/kalesky/ 如果對你有用的話歡迎點贊關註喲! ​​​​​​​ ...


(防扒小助手)

本人CSDN博客:

https://blog.csdn.net/m0_61753302

本人博客園博客(同步CSDN):

何以牽塵 - 博客園 (cnblogs.com)https://www.cnblogs.com/kalesky/

如果對你有用的話歡迎點贊關註喲!

 

​​​​​​​

目錄

1、實驗目標概述

2、實驗環境配置

2.1 實驗環境

2.2 GitHub Lab3倉庫的URL地址

3、實驗過程

3.1 待開發的三個應用場景

3.1.1 應用場景

3.1.2 共性需求

3.1.3 差異

3.2 ADT識別與設計

3.2.1 任務1:投票類型VoteType

3.2.2 投票項VoteItem

3.2.3 任務3:選票Vote

3.2.4 任務4:投票活動Poll的測試

3.2.5 任務5:投票活動Poll的實現類GeneralPollImpl

3.2.6 任務6:投票活動Poll的子類型

3.3 ADT行為的設計與實現

3.3.1 任務7:合法性檢查

3.3.2 任務8:採用Strategy設計模式實現靈活的計票規則

3.3.3 任務9:採用Strategy設計模式實現靈活的遴選規則

3.3.4 任務10:處理匿名和實名投票

3.3.5 任務11:採用Visitor設計模式實現功能擴展

3.3.6 任務12:基於語法的數據讀入

3.4 任務13:應用設計與開發

3.4.1 商業表決系統

3.4.2 代表選舉系統

3.4.3 聚餐點菜系統

3.5 任務14:應對面臨的新變化

3.5.1 商業表決應用:可以一次表決多個商業提案

3.5.2 代表選舉應用:遴選規則變化

3.5.3 聚餐點菜應用:取消權重設置、只計算“喜歡”的票數

​​​​​​​3.6 Git倉庫結構

4、實驗進度記錄

5、實驗過程中遇到的困難與解決途徑

6、實驗過程中收穫的經驗、教訓、感想

6.1 實驗過程中收穫的經驗和教訓(必答)

​​​​​​​6.2 針對以下方面的感受(必答)


 

 

1、實驗目標概述

本次實驗覆蓋課程第 23 章的內容,目標是編寫具有可復用性和可維護性

的軟體,主要使用以下軟體構造技術:

  •  子類型、泛型、多態、重寫、重載
  •  繼承、委派、CRP
  •  語法驅動的編程、正則表達式
  •  設計模式

本次實驗給定了多個具體應用,學生不是直接針對每個應用分別編程實現,而是通過 ADT 和泛型等抽象技術,開發一套可復用的 ADT 及其實現,充分考慮這些應用之間的相似性和差異性,使 ADT 有更大程度的復用(可復用性)和更容易面向各種變化(可維護性)。

2、實驗環境配置

2.1 實驗環境

Intellij IDEA 2022.1(Ultimate Edition)

 

2.2 GitHub Lab3倉庫的URL地址

略。

 

3、實驗過程

3.1 待開發的三個應用場景

3.1.1 應用場景

① 商業表決(BusinessVoting)

面向某個商業公司,其內部成員提出某個商業提案(例如“關於投資 xx 項目的提案”),公司董事會的各位董事對其進行實名錶決(支持、反對、棄權),各董事在表決中的權重取決於其所持有的公司股票的比例,根據該持股比例對投票結果進行計算,若“支持”票的比例超過2/3,則該提案通過,否則該提案不通過。

② 代表選舉(Election)

針對某次活動(例如哈工大學生代表大會),需要從一群候選人中選出若幹人,作為代表參加活動。在該選舉中,提前確定一部分候選人,投票人從已確定的候選人中選取,不可提名新的候選人。計劃選出的代表數量是提前確定的。投票人針對每個候選人匿名選擇“支持、反對、棄權”之一,但選擇“支持”的人數不能高於計劃選出的代表數量,否則為非法票。所有投票人的權重均相等。

③ 聚餐點菜(DinnerOrder)

一群人去餐館就餐,需要從該餐館提供的菜單中選擇若幹道菜,點菜的數量要大於等於就餐總人數,且小於總人數+5。每個人針對菜單上的每一道菜實名錶達自己的喜好(喜歡、不喜歡、無所謂),選擇這三個選項的數目無限制。不同人的身份不同,其偏好的影響力會有所不同(例如家庭聚餐時,老人的權重更大、子女的權重更小,見下表黃色部分)。所有人表達觀點之後,根據影響力加權計票(喜歡、不喜歡、無所謂分別得分201),取總得分最高的前k道菜。

 

3.1.2 共性需求

 

3.1.3 差異

 

 

 

3.2 ADT識別與設計

3.2.1 任務1:投票類型VoteType

(1)測試策略

根據VoteType中方法的spec,對checkLegality和getScoreByOption方法進行設計測試。

checkLegality():

通過對已有的投票類型和未出現的投票類型進行checkLegality的正確性測試。

getScoreByOption():

給定的投票選項的名稱,通過測試其getScoreByOption返回的值是否與給定值相等進行正確性的判斷。

 

(2)欄位和方法

① spec規約

<1> Rep Invariants

選項應該至少有2個,每個選項的長度不超過5,且不允許出現空格。

<2> Abstract Function

使用options實現的函數對應關係的映射。

<3> Safety from Rep Exposure

必要時使用防禦性拷貝防止表示泄露。

 

② 欄位:

<1> private Map<String, Integer> options = new HashMap<>();

key表示選項名字,value表示該選項所對應的權重。

<2> private String support;

用來記錄哪個選項表示支持。

 

③ 方法:

<1> private boolean checkRep()

檢查不變性:如果有選項名稱長度超過5或者少於兩個選項,則返回false,否則返回true。

<2> public VoteType()

預設使用“支持”(1)|“反對”(-1)|“棄權”(0)這三種投票選項。

<3> public VoteType(Map<String, Integer> origin)

傳入一個給定的Map類型參數,建立一個VoteType類型的對象。

<4> public VoteType(String regex)

根據滿足特定語法規則的字元串,創建一個投票類型對象。

<5> public boolean checkLegality(String option)

判斷一個投票選項是否合法(用於Poll中對選票的合法性檢查)。

<6> public int getScoreByOption

根據一個投票選項,得到其對應的分數。

<7> public String getSupport()

返回VoteType中的支持選項的選項名。

 

(3)測試結果

測試結果運行如下:

 

3.2.投票項VoteItem<C>

(1)測試策略

根據VoteItem中方法的spec,對getCandidate和getVoteValue方法進行設計測試。

getCandidate():

給定一個投票項,通過觀察調用getCandidate()返回值是否為給定的candidate。

getVoteValue():

給定一個投票項,通過觀察調用getVoteValue()返回值是否為給定的value。

 

(2)欄位和方法

① spec規約

<1> Rep Invariants

選項名稱不允許出現空格。

<2> Abstract Function

投票選項對候選人類型及String類型的映射

<3> Safety from Rep Exposure

欄位使用private,必要時使用防禦性拷貝防止表示泄露。

 

② 欄位

<1> private C candidate

本投票項所針對的候選對象

<2> private String value;

對候選對象的具體投票選項,例如“支持”、“反對”等

 

③ 方法

<1> private boolean checkRep()

檢查不變性:如果有選項名稱長度超過5或者出現空格,則返回false,否則返回true。

<2> public VoteItem(C candidate, String value)

創建一個投票項對象

<3> public String getVoteValue()

得到該投票選項的具體投票項

<4> public C getCandidate()

得到該投票選項所對應的候選人

 

(3)測試結果

測試結果運行如下:

 

3.2.3 任務3:選票Vote

(1)測試策略

根據VoteItem中方法的spec,對getCandidate和getVoteValue方法進行設計測試。

getCandidate():

給定一個投票項,通過觀察調用getCandidate()返回值是否為給定的candidate。

getVoteValue():

給定一個投票項,通過觀察調用getVoteValue()返回值是否為給定的value。

 

(2)欄位和方法

① spec規約

<1> Rep Invariants

合法的voteItem

<2> Abstract Function

對應到自己的成員變數

<3> Safety from Rep Exposure

rep均為private,採用防禦式拷貝

② 欄位

<1> static private int num

已經產生了多少票,用於為id計數

<2> private int id;

用於標記投票的序號

<3> private Set<VoteItem<C>> voteItems

一個投票人對所有候選對象的投票項集合

<4> private Calendar date

投票時間

 

③方法

<1>public Vote(Set<VoteItem<C>> voteItems)

創建一個選票對象

<2>public Set<VoteItem<C>> getVoteItems()

查詢該選票中包含的所有投票項

<3>public boolean candidateIncluded(C candidate)

一個特定候選人是否包含本選票中

 

(3)測試結果

測試結果運行如下:

 

3.2.4 任務4:投票活動Poll<C>的測試

(1)測試策略:

由於Poll<C>介面中的方法均為void類型,故採用getter方法對其操作結果進行觀察,比較與預期結果是否相同,通過此策略進行測試。

(2)測試方法:

① setInfo()

 

 

② addCandidates()

 

③ addVoters()

 

④ addVote()

 

3.2.5 任務5:投票活動Poll<C>的實現類GeneralPollImpl

(1)spec規約

<1> Rep Invariants
quantity為整數
<2> Abstract Function
映射到實際的一次投票活動
<3> Safety from Rep Exposure
用protected防止泄露和必要的防禦性拷貝

 

(2)欄位和方法

① rep

<1> 投票活動的名稱
protected String name;
<2> 投票活動發起的時間
protected Calendar date;
<3> 候選對象集合
protected List<C> candidates;
<4> 投票人集合,key為投票人,value為其在本次投票中所占權重
protected Map<Voter, Double> voters;
<5> 擬選出的候選對象最大數量
protected int quantity = Integer.MAX_VALUE;
<6> 本次投票擬採用的投票類型(合法選項及各自對應的分數)
protected VoteType voteType;
<7> 所有選票集合
protected Set<Vote<C>> votes = new HashSet<>();
<8> 計票結果,key為候選對象,value為其得分
protected Map<C, Double> statistics;
<9> 遴選結果,key為候選對象,value為其排序位次
protected Map<C, Double> results;
<10> 非法選票的集合
protected Set<Vote<C>> illegalVotes = new HashSet<>();

 

② 方法

<1> private boolean checkRep()

檢查不變數:quantity需要大於0

<2> public void setInfo(String name, Calendar date, VoteType type, int quantity)

設置投票活動的相關信息

<3> public void addVoters(Map<Voter, Double> voters)

向投票活動中添加voters及其對應的權重

<4> public void addCandidates(List<C> candidates)

向投票活動中添加candidates

<5> protected boolean isLegal(Vote<C> vote)

檢查投票是否合法

<6> public void addVote(Vote<C> vote)

想投票活動中添加選票

<7> protected boolean checkVotes(Set<Vote<C>> votes)

檢查票的合法性

<8> public void statistics(StatisticsStrategy<C> ss)

按規則計票

<9> public void selection(SelectionStrategy<C> ss)

按規則遴選

<10> public String result()

輸出遴選結果

<11> 額外構造的輔助方向(如getter方法)如下

public void accept(Visitor visitor);
public String getName();
public Calendar getDate();
public Set<Vote<C>> getVotes();
public Map<Voter, Double> getVoters();
public Set<Vote<C>> getIllegalVotes();
public List<C> getCandidates();
public int getQuantity();
public VoteType getVoteType();
public String toString();

 

(3)測試結果

測試結果如下:

 

3.2.6 任務6:投票活動Poll<C>的子類型

(1)BusinessVoting

需要重寫addVote和checkVotes方法

候選對象數量只能為1,必須為實名投票,在計算得票時還需考慮投票人所占權重。

① addVote方法重寫如下:

先檢查vote是否為實名投票,再檢查vote是否合法,若vote不合法或者voters中未包含該vote的投票人,則將該選票列入illegalVotes集合中。

 

 

checkVotes方法重寫如下:

對於votes中的每一個vote,如果vote的voter不包含在該投票活動poll的voters中,則將該選票列入illegalVotes集合中。若在已投票的投票人集合votedVoter中包含了該voter,則將該投票人列入reVoters中,併在之後的計票活動中將重覆投票的voter的選票不計入在內。

 

(2)Election

需要檢查一個投票人投的支持票總數是否小於等於候選對象數量,該投票活動支持匿名投票。所有投票人的權重均相同。

① 增添一個新方法supportCount

用於返回一個選票內的贊成票數量。

 

② 重寫addVote方法:

對vote進行判斷,如果vote非法,則將其加入非法選票集合illegalVotes。 如果該投票人投的支持票數量大於候選人數量,也將其加入非法選票集合illegalVotes。

 

(3)DinnerOrder

需要重寫addVote和checkVotes方法

必須為實名投票,在計算得票時還需考慮投票人所占權重。

① addVote方法重寫如下:

先檢查vote是否為實名投票,再檢查vote是否合法,若vote不合法或者voters中未包含該vote的投票人,則將該選票列入illegalVotes集合中。

 

checkVotes方法重寫如下:

對於votes中的每一個vote,如果vote的voter不包含在該投票活動poll的voters中,則將該選票列入illegalVotes集合中。若在已投票的投票人集合votedVoter中包含了該voter,則將該投票人列入reVoters中,併在之後的計票活動中將重覆投票的voter的選票不計入在內。

 

(4)測試結果

① BusinessVotingTest

Junit測試結果如下:

 

② ElectionTest

Junit測試結果如下:

 

③ DinnerOrderTest

Junit測試結果如下:

 

3.3 ADT行為的設計與實現

3.3.1 任務7:合法性檢查

GeneralPollImpl中將合法性檢查的行為抽取到一個單獨的方法isLegal之中進行合法性檢查:

對一張選票的各投票選項進行考察,若投票選項與候選人數目不相同,則返回非法值false。

之後對投票選項進行遍歷每一個投票,若所投票的對象不包含在本次投票的候選人之中,或者投票的類型與所投值不相符號,則返回非法值false。

 在addVote方法中對isLegal方法進行調用即可:

 

並將isLegal判斷所對應的非法選票加入到非法選票的集合illegalVotes中。

 

3.3.2 任務8:採用Strategy設計模式實現靈活的計票規則

(1)BusinessStatistics計票規則

遍歷Vote<Proposal>類型的votes集合中的每一張選票vote。若vote在非法選票集合illegalVotes中,則不計入該選票。

由於BusinessVoting是實名投票,故需要獲取投票人的權重以便進行最終結果的計算。

對每一張選票vote的每一個投票選項VoteItem<Proposal>進行遍歷,在還沒進行遍歷之前先對議案的結果進行初始化,如果投票選項的值為正數,則表示支持,通過加權計入相應proposal的計票結果中。

 

(2)ElectionStatistics計票規則

遍歷Vote<Person>類型的votes集合中的每一張選票vote。若vote在非法選票集合illegalVotes中,則不計入該選票。

由於Election是匿名投票,所以不需要獲取投票人的權重等信息。

對每一張選票vote的每一個投票選項VoteItem<Proposal>進行遍歷,在還沒進行遍歷之前先對議案的結果進行初始化,如果投票選項的值為正數,則表示支持,相加計入相應person的計票結果中。

 

(3)DinnerStatistics計票規則

遍歷Vote<Dish>類型的votes集合中的每一張選票vote。若vote在非法選票集合illegalVotes中,則不計入該選票。

由於DinnerOrder是實名投票,故需要獲取投票人的權重以便進行最終結果的計算。

對每一張選票vote的每一個投票選項VoteItem<Dish>進行遍歷,在還沒進行遍歷之前先對議案的結果進行初始化,對所給的投票值通過加權計入相應dish的計票結果中。

 

3.3.3 任務9:採用Strategy設計模式實現靈活的遴選規則

(1)BusinessSelection遴選規則

初始化proposal的占比為0.0,本規則對Business進行了擴展,可同時提出多個proposal而不僅限於一個proposal,以適應未來任務的要求。

若對應proposal的計票結果超過了2/3,則將其放入result中傳出給結果。即遴選出最終方案。

 

 

(2)ElectionSelection遴選規則

首先將所有候選人放入TreeSet中利用TreeSet進行排序:

Set<Person> set = new TreeSet<>(new Comparator<Person>() {
    @Override
    public int compare(Person o1, Person o2) {
        if(statistics.get(o1) > statistics.get(o2)) return -1;
        else if(statistics.get(o1) < statistics.get(o2)) return 1;
        return o1.getName().compareTo(o2.getName());
    }
});
set.addAll(statistics.keySet());

Election要求根據支持票數量排序,前k個候選人當選;若有多個候選人的支持票數量相等而無法自然排出前k名,則僅有那些明確可進入前k名的人當選。

因此需要判斷第k名和第k+1名的分數是否相同,若得分不同,則取出這前k名作為最終結果傳遞給result輸出。若得分相同則需要從頭重新遍歷,取出前面與這第k名的分數不同的所有候選人Person,傳遞給result輸出。

double rank = 0.0, score = Integer.MIN_VALUE;
Iterator<Person> iterator = set.iterator();
for(int i = 0; i < Math.min(quantity, statistics.size()); i++) {
    score = statistics.get(iterator.next());
}
if(!iterator.

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、分庫分表解決的現狀問題 解決資料庫本身瓶頸 連接數: 連接數過多時,就會出現‘too many connections’的錯誤,訪問量太大或者資料庫設置的最大連接數太小的原因 Mysql預設的最大連接數為100.可以修改,而mysql服務允許的最大連接數為16384 資料庫分表可以解決單表海量數 ...
  • #反射機制 AVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。 Java反射機制在框架設計中極為廣泛,需要深入理解。 ##反射基礎 RTTI(R ...
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • MySQL之JDBC 一、JDBC是什麼 Java DatabaseConnectivity (java語言連接資料庫) 二、JDBC的本質 JDBC是SUN公司制定的一套介面(interface)。 介面都有調用者和實現者。 面向介面調用、面向介面寫實現類,這都屬於面向介面編程。 三、為什麼要面向 ...
  • 1.認識shiro 除Spring Security安全框架外,應用非常廣泛的就是Apache的強大又靈活的開源安全框架 Shiro,在國內使用量遠遠超過Spring Security。它能夠用於身份驗證、授權、加密和會話管理, 有易於理解的API,可以快速、輕鬆地構建任何應用程式。而且大部分人覺得 ...
  • 面向對象編程(高級) 筆記目錄:(https://www.cnblogs.com/wenjie2000/p/16378441.html) 類變數和類方法(static) 類變數 類變數-提出問題 提出問題的主要目的就是讓大家思考解決之道,從而引出我要講的知識點.說:有一群小孩在玩堆雪人,不時有新的小 ...
  • Java常用類(一) 一、String 類:(不可變的字元序列) 1.1 String:字元串,使用一對 " " 引起來表示。 String 類聲明為 final 的,不可被繼承。 String 類實現了 Serializable 介面:表示字元串是支持序列化的。實現了 Comparable 介面: ...
  • 哈嘍兄弟們,又是新的一天!今天你敲代碼了嗎? 一、序言 為什麼要挑戰自己在代碼里不寫 for loop?因為這樣可以迫使你去學習使用比較高級、比較地道的語法或 library。文中以 python 為例子,講了不少大家其實在別人的代碼里都見過、但自己很少用的語法。 自從我開始探索 Python 中驚 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...