记一个Java问题
一个在线阅读网站,有若干书籍,每本书籍有若干章节,每个章节有若干字数,假设在线十万用户阅读。
1. 用户可随时查询任何一本书的当前阅读用户数;
2. 用户可以随时查询任何一个章节的当前阅读用户数;
3. 管理员可以随时查询所有用户的大概阅读字数。
以下是我的解答,请网友们勘正:
1. 用户类:
import java.io.Serializable; import java.util.Objects; public class User implements Serializable { private static final long serialVersionUID = 5034080277810208601L; private String name; public User(String name) { Objects.requireNonNull(name, "name can't be null."); this.setName(name); } @Override public int hashCode() { int result = 17; result = 31 * result + (name == null ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (obj instanceof User) { User model = (User) obj; if (Objects.equals(this.getName(), model.getName())) { return true; } } return false; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
2. 图书和章节类
import java.io.Serializable; import java.util.LinkedList; import java.util.List; import java.util.Objects; public class Book implements Serializable { private static final long serialVersionUID = 6291337232685852509L; private String name; private List<Chapter> chapters = new LinkedList<>(); public Book(String name) { Objects.requireNonNull(name, "name can't be null."); this.setName(name); } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int hashCode() { int result = 17; result = 31 * result + (name == null ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (obj instanceof Book) { Book model = (Book) obj; if (!Objects.equals(this.getName(), model.getName())) { return false; } if (this.getChapters().size() != model.getChapters().size()) { return false; } for (int i = 0; i < this.getChapters().size(); i++) { if (!Objects.equals(this.getChapters().get(i), model.getChapters().get(i))) { return false; } } return true; } return false; } public List<Chapter> getChapters() { return chapters; } public void setChapters(List<Chapter> chapters) { this.chapters = chapters; } public void addChapter(Chapter chapter) { this.chapters.add(chapter); } public static class Chapter implements Serializable { private static final long serialVersionUID = 6374103860999522235L; private Book book; private String name; private int wordCount; public Chapter(Book book, String name, int wordCount) { Objects.requireNonNull(book, "book can't be null."); Objects.requireNonNull(name, "name can't be null."); this.setBook(book); this.setName(name); if (wordCount < 1) { throw new IllegalArgumentException("Illegal value for wordCount which must exceed 0."); } this.setWordCount(wordCount); } @Override public int hashCode() { int result = 17; result = 31 * result + (name == null ? 0 : name.hashCode()); result = 31 * result + wordCount; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (obj instanceof Chapter) { Chapter model = (Chapter) obj; if (Objects.equals(this.getName(), model.getName()) && this.getWordCount() == model.getWordCount()) { return true; } } return false; } public Book getBook() { return book; } public void setBook(Book book) { this.book = book; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getWordCount() { return wordCount; } public void setWordCount(int wordCount) { this.wordCount = wordCount; } } }
3. 读物统计类:
import java.util.LinkedHashMap; import java.util.concurrent.atomic.AtomicInteger; public class ReadingMaterialStatistic<R> extends LinkedHashMap<R, AtomicInteger> { private static final long serialVersionUID = -8772739941097264921L; public void read(R readingMaterial, R lastReadingMaterial) { if (readingMaterial.equals(lastReadingMaterial)) { return; } finish(lastReadingMaterial); read(readingMaterial); } private synchronized void read(R readingMaterial) { AtomicInteger counter = super.get(readingMaterial); if (counter == null) { counter = new AtomicInteger(); super.put(readingMaterial, counter); } counter.incrementAndGet(); } private void finish(R readingMaterial) { if (readingMaterial == null) { return; } super.get(readingMaterial).addAndGet(-1); } }
4. 读者统计类:
import java.util.LinkedHashMap; public class ReaderStatistic<C extends Book.Chapter, U extends User> extends LinkedHashMap<U, C> { private static final long serialVersionUID = -6365084760182051147L; /** * Word count that reader already has been read. */ private volatile int wordCount; public synchronized C read(U user, C chapter) { wordCount += chapter.getWordCount(); return this.put(user, chapter); } public int getWordCount() { return wordCount; } }
5. 总处理类
import java.util.concurrent.atomic.AtomicInteger; import core.web.commercialalibaba.Book.Chapter; public class ReadHandler { private ReadingMaterialStatistic<Book> bookStatistic = new ReadingMaterialStatistic<>(); private ReadingMaterialStatistic<Book.Chapter> chapterStatistic = new ReadingMaterialStatistic<>(); private ReaderStatistic<Book.Chapter, User> readerStatistic = new ReaderStatistic<>(); /** * Read api */ public void read(User user, Chapter chapter) { Chapter lastChapter = readerStatistic.read(user, chapter); Book lastBook = null; if (lastChapter != null) { lastBook = lastChapter.getBook(); } bookStatistic.read(chapter.getBook(), lastBook); chapterStatistic.read(chapter, lastChapter); } /** * Reader count for specific book. */ public int readerCount4Book(Book book) { AtomicInteger counter = bookStatistic.get(book); if (counter == null) { return 0; } return counter.get(); } /** * Reader count for specific chapter. */ public int readerCount4Chapter(Book.Chapter chapter) { AtomicInteger counter = chapterStatistic.get(chapter); if (counter == null) { return 0; } return counter.get(); } /** * All read word count */ public int readWordCount() { return readerStatistic.getWordCount(); } }