记一个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();
    }
}

 

posted @ 2021-06-22 22:34  白马黑衣  阅读(73)  评论(0编辑  收藏  举报