再一次的重構,這次就是討論類的職責和對象文件的封裝內容。類的職責,指的是我們一個類到底應該做什么?做多少?以我的圖書館仿真為例,顯然,主類的職責之一就是顯示結果,就是圖書館圖書列表。但是,在圖書館列表這個部分,需要實現很多方法,而這些方法是否都需要在主類里實現呢?就像前面的例子那樣,這次我們依然是有三個類:RatingBook,BookDepot和main,那么,它們各自應該承擔的職責是什么呢?我們可以將目光先放在那些涉及到RatingBook的方法上。首先,RatingBook就像所有的對象文件一樣,應該有設置數據屬性和返回數據屬性的方法,當然還有構造器。一般,一開始設計類的時候應該遵守的原則就是,職責盡可能簡單,這樣可讀性才會高。
接着就是BookDepot。這個類的最大職責就是產生Book,但是由於我自己單方面的設定是在一個String數組里隨機產生,為了貼近真實情況,需要將一些重復的去除掉。本來這部分的代碼是放在主類里,但是后來我將它放在BookDepot中,因為我覺得,這個類最主要的功能就是能夠返回一個BookList,那么,作為附加的要求,返回一個不重復的BookList就能減少代碼的邏輯冗余(所謂的邏輯冗余,就是一段代碼中包含太多不相關的邏輯),這並沒有不妥。而且,我這里將它作為靜態方法,是因為我需要在兩個地方得到bookList,但是如果我要在兩個地方都new一個BookDepot,所以我將它變成靜態方法,這樣就無需每次 使用時都需創建一個根本沒有用到的對象。
最后就是主類。當然,經過上面這樣的修改,主類的邏輯已經簡潔很多,它最主要的工作就是對List進行加工,這些加工是可以放在主類里的,如果將它們放在BookDepot里,那么這個對象文件承擔的職責就過多了,而且有些並不是我們這個對象產生文件應該去處理的,它最主要的功能就是產生我們想要的不重復List,至於這個List的加工,應該交給其他類處理,當然,如果我們想要寫個加工類也是可以的,但是這樣主類就只是啟動加工類而已,這種處理我覺得是將類的職責過分的細分,類的職責的確需要細分,這是重構的很重要的原則,但是盲目的細分並不是一個正確的選擇,所以,主類還是必須承擔一定的職責。
綜合上述,我認為,類應該承擔多少職責,這個問題應該與我們的邏輯分類有關,就像我的例子那樣,所有的邏輯可以分為BookList的產生,RatingBook的設置,以及對BookList的加工這三部分,那么,就有三個職責類,然后由這三個職責類來處理這些邏輯。這對於對象文件來說同樣適用,對象文件封裝的邏輯應該是與其自身相關的邏輯,但是,必須要意識到一點,就是對象文件的邏輯最好不要包含有其他對象的信息,尤其是對象的創建。
最后,就是想要說一下方法名的命名問題,我認為,可讀性高的代碼,並不是一定要有詳盡的注釋,事實上,方法名和參數列表就已經是最好的注釋了,只要方法名得當,我們完全可以將方法名當做一個注釋來看,所以,方法名是很重要的,當然,方法名是要根據方法的功能和參數列表來決定,這個真的是需要很高的素養才能做到,像是我的例子,就真的是很難達到要求,這需要我們在實踐中不斷摸索。
這次的重構,再次暴露了我編程素養極低的弱點,甚至連一些基本的常識都不知道,比如說,一般名字前帶有m的是類的成員變量,帶有s的是static成員,但是我都不知道,一直以來都是隨便命名,可見沒有多看別人代碼的壞處是如此明顯!而且,我還發現,如果在代碼創建這個類只是為了調用它里面的一個方法,就沒有其他用途,那么,請把這個方法設為static,因為這樣就不用每次都創建無用的類實例。
這個例子遠遠沒有完成,因為它里面還有很多我需要去思考的東西,直到我認為它已經幾乎沒有問題。
public class Library { public static void main(String[] args) throws InterruptedException, IOException { searchBookAndGetResultOfSearch(); }
private static void searchBookAndGetResultOfSearch(String name) throws IOException { String name = enterAndGetName();
List<RatingBook> list = getBookListFromZhongZhuanTaiByName(name); List<RatingBook> depotList = BookDepot.createBookListFromDepot(10, 1); List<RatingBook> bookList = getListContainsName(name, depotList); for (RatingBook libraryBook : bookList) { for (RatingBook zhongZhuanTaiBook : list) { if ((libraryBook.getName()) .equals((zhongZhuanTaiBook.getName()))) { libraryBook.setRating(zhongZhuanTaiBook.getRating()); } } } showList("圖書館里的圖書列表:", bookList); }
private static String enterAndGetName() throws IOException {
BufferedReader name = new BufferedReader(new InputStreamReader(System.in));
String entername = name.readLine().toLowerCase();
return entername;
}
private static List<RatingBook> getBookListFromZhongZhuanTaiByName( String name) { List<RatingBook> list = BookDepot.createBookListFromDepot(10, 6); List<RatingBook> containsBook = getListContainsName(name, list); showList("中轉台圖書列表:", list); showList("中轉台符合條件的圖書:", containsBook); return list; } private static List<RatingBook> getListContainsName(String name, List<RatingBook> list) { List<RatingBook> bookList = new ArrayList<RatingBook>(); for (RatingBook ratingBook : list) { String book = ratingBook.getName().toLowerCase(); if (book.contains(name)) { bookList.add(ratingBook); } } return bookList; } private static void showList(String string, List<RatingBook> list) { sortBookByRating(list); System.out.println(string); for (RatingBook book : list) { System.out.println(book.getName() + "評分:" + book.getRating()); } } private static void sortBookByRating(List<RatingBook> list) { for (int i = 0; i < list.size() - 1; i++) { for (int j = i + 1; j < list.size(); j++) { if ((list.get(i).getRating()) <= (list.get(j).getRating())) { String temp = list.get(i).getName(); int rating = list.get(i).getRating(); list.get(i).setName(list.get(j).getName());
list.get(i).setRating(list.get(j).getRating());
list.get(i).setName(temp);
list.get(i).setRating(rating);
} } } } }
public class RatingBook { private int mRating = 0; private String mName = ""; public RatingBook() {} public RatingBook(String name, int rating) { mName = name; mRating = rating; } public void setRating(int rating) { mRating = rating; } public void setName(String name) { mName = name; } public String getName() { return mName; } public int getRating() { return mRating; } }
public class BookDepot { static String[] sBookDepot = { "java and javascript", "java and C++", "java and c", "sql", "CEHNJINSHENG", "java", "C++", "javascript", "Java", "java and C", "java and SQL", "chenjinsehng", "int" }; static List<RatingBook> createBookListFromDepot(int num, int rating) { List<RatingBook> list = new ArrayList<RatingBook>(); int len = new Random().nextInt(num);
for (int i = 0; i < len; i++) { RatingBook book = new RatingBook(sBookDepot[len], returnRandom(rating)); list.add(book); } List<RatingBook> newList = removeSameBookFromList(list); return newList; } private static List<RatingBook> removeSameBookFromList(List<RatingBook> list) { Map<String, Integer> map = createMapWithSingalKeyOfBookName(list); List<RatingBook> bookList = new ArrayList<RatingBook>(); @SuppressWarnings("rawtypes") Set entries = map.entrySet(); if (entries != null) { @SuppressWarnings("rawtypes") Iterator iterator = entries.iterator(); while (iterator.hasNext()) { @SuppressWarnings("rawtypes") Map.Entry entry = (Entry) iterator.next(); String key = (String) entry.getKey(); Integer value = (Integer) entry.getValue(); RatingBook book = new RatingBook(); book.setBook(key, value); bookList.add(book); } } return bookList; } private static Map<String, Integer> createMapWithSingalKeyOfBookName( List<RatingBook> list) { Map<String, Integer> map = new HashMap<String, Integer>(); for (RatingBook book : list) { map.put(book.getName(), book.getRating()); } return map; } }