forked from ashishps1/awesome-low-level-design
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
311 additions
and
197 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,72 @@ | ||
package stackoverflow; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Date; | ||
import java.util.List; | ||
|
||
public class Answer { | ||
public class Answer implements Votable, Commentable { | ||
private final int id; | ||
private final String body; | ||
private final String content; | ||
private final User author; | ||
private final Question question; | ||
private boolean isAccepted; | ||
private final Date creationDate; | ||
private final List<Comment> comments; | ||
private int voteCount; | ||
private final List<Vote> votes; | ||
|
||
public Answer(int id, String body, User author, Question question, List<Comment> comments, int voteCount) { | ||
this.id = id; | ||
this.body = body; | ||
public Answer(User author, Question question, String content) { | ||
this.id = generateId(); | ||
this.author = author; | ||
this.question = question; | ||
this.comments = comments; | ||
this.voteCount = voteCount; | ||
this.content = content; | ||
this.creationDate = new Date(); | ||
this.votes = new ArrayList<>(); | ||
this.comments = new ArrayList<>(); | ||
this.isAccepted = false; | ||
} | ||
|
||
public void setVoteCount(int voteCount) { | ||
this.voteCount = voteCount; | ||
@Override | ||
public void vote(User user, int value) { | ||
if (value != 1 && value != -1) { | ||
throw new IllegalArgumentException("Vote value must be either 1 or -1"); | ||
} | ||
votes.removeIf(v -> v.getUser().equals(user)); | ||
votes.add(new Vote(user, value)); | ||
author.updateReputation(value * 10); // +10 for upvote, -10 for downvote | ||
} | ||
|
||
public int getId() { | ||
return id; | ||
@Override | ||
public int getVoteCount() { | ||
return votes.stream().mapToInt(Vote::getValue).sum(); | ||
} | ||
|
||
public String getBody() { | ||
return body; | ||
@Override | ||
public void addComment(Comment comment) { | ||
comments.add(comment); | ||
} | ||
|
||
public User getAuthor() { | ||
return author; | ||
@Override | ||
public List<Comment> getComments() { | ||
return new ArrayList<>(comments); | ||
} | ||
|
||
public Question getQuestion() { | ||
return question; | ||
public void markAsAccepted() { | ||
if (isAccepted) { | ||
throw new IllegalStateException("This answer is already accepted"); | ||
} | ||
isAccepted = true; | ||
author.updateReputation(15); // +15 reputation for accepted answer | ||
} | ||
|
||
public List<Comment> getComments() { | ||
return comments; | ||
private int generateId() { | ||
return (int) (System.currentTimeMillis() % Integer.MAX_VALUE); | ||
} | ||
|
||
public int getVoteCount() { | ||
return voteCount; | ||
} | ||
} | ||
// Getters | ||
public int getId() { return id; } | ||
public User getAuthor() { return author; } | ||
public Question getQuestion() { return question; } | ||
public String getContent() { return content; } | ||
public Date getCreationDate() { return creationDate; } | ||
public boolean isAccepted() { return isAccepted; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,27 @@ | ||
package stackoverflow; | ||
|
||
import java.security.Timestamp; | ||
import java.util.Date; | ||
|
||
public class Comment { | ||
private int id; | ||
private String text; | ||
private User author; | ||
private Timestamp createdAt; | ||
} | ||
private final int id; | ||
private final String content; | ||
private final User author; | ||
private final Date creationDate; | ||
|
||
public Comment(User author, String content) { | ||
this.id = generateId(); | ||
this.author = author; | ||
this.content = content; | ||
this.creationDate = new Date(); | ||
} | ||
|
||
private int generateId() { | ||
return (int) (System.currentTimeMillis() % Integer.MAX_VALUE); | ||
} | ||
|
||
// Getters | ||
public int getId() { return id; } | ||
public User getAuthor() { return author; } | ||
public String getContent() { return content; } | ||
public Date getCreationDate() { return creationDate; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package stackoverflow; | ||
|
||
import java.util.List; | ||
|
||
public interface Commentable { | ||
void addComment(Comment comment); | ||
List<Comment> getComments(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,76 @@ | ||
package stackoverflow; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Date; | ||
import java.util.List; | ||
|
||
public class Question { | ||
public class Question implements Votable, Commentable { | ||
private final int id; | ||
private final String title; | ||
private final String body; | ||
private final String content; | ||
private final User author; | ||
private final Date creationDate; | ||
private final List<Answer> answers; | ||
private final List<Comment> comments; | ||
private final List<Tag> tags; | ||
private int voteCount; | ||
private final List<Vote> votes; | ||
|
||
public Question(int id, String title, String body, User author, List<Answer> answers, List<Comment> comments, List<Tag> tags, int voteCount) { | ||
this.id = id; | ||
this.title = title; | ||
this.body = body; | ||
public Question(User author, String title, String content, List<String> tagNames) { | ||
this.id = generateId(); | ||
this.author = author; | ||
this.answers = answers; | ||
this.comments = comments; | ||
this.tags = tags; | ||
this.voteCount = voteCount; | ||
} | ||
|
||
public void setVoteCount(int voteCount) { | ||
this.voteCount = voteCount; | ||
} | ||
|
||
public int getId() { | ||
return id; | ||
this.title = title; | ||
this.content = content; | ||
this.creationDate = new Date(); | ||
this.answers = new ArrayList<>(); | ||
this.tags = new ArrayList<>(); | ||
this.votes = new ArrayList<>(); | ||
this.comments = new ArrayList<>(); | ||
for (String tagName : tagNames) { | ||
this.tags.add(new Tag(tagName)); | ||
} | ||
} | ||
|
||
public String getTitle() { | ||
return title; | ||
public void addAnswer(Answer answer) { | ||
if (!answers.contains(answer)) { | ||
answers.add(answer); | ||
} | ||
} | ||
|
||
public String getBody() { | ||
return body; | ||
@Override | ||
public void vote(User user, int value) { | ||
if (value != 1 && value != -1) { | ||
throw new IllegalArgumentException("Vote value must be either 1 or -1"); | ||
} | ||
votes.removeIf(v -> v.getUser().equals(user)); | ||
votes.add(new Vote(user, value)); | ||
author.updateReputation(value * 5); // +5 for upvote, -5 for downvote | ||
} | ||
|
||
public User getAuthor() { | ||
return author; | ||
@Override | ||
public int getVoteCount() { | ||
return votes.stream().mapToInt(Vote::getValue).sum(); | ||
} | ||
|
||
public List<Answer> getAnswers() { | ||
return answers; | ||
@Override | ||
public void addComment(Comment comment) { | ||
comments.add(comment); | ||
} | ||
|
||
@Override | ||
public List<Comment> getComments() { | ||
return comments; | ||
return new ArrayList<>(comments); | ||
} | ||
|
||
public List<Tag> getTags() { | ||
return tags; | ||
private int generateId() { | ||
return (int) (System.currentTimeMillis() % Integer.MAX_VALUE); | ||
} | ||
|
||
public int getVoteCount() { | ||
return voteCount; | ||
} | ||
} | ||
// Getters | ||
public int getId() { return id; } | ||
public User getAuthor() { return author; } | ||
public String getTitle() { return title; } | ||
public String getContent() { return content; } | ||
public Date getCreationDate() { return creationDate; } | ||
public List<Answer> getAnswers() { return new ArrayList<>(answers); } | ||
public List<Tag> getTags() { return new ArrayList<>(tags); } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,100 +1,77 @@ | ||
package stackoverflow; | ||
|
||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import java.util.stream.Collectors; | ||
|
||
public class StackOverflow { | ||
private static StackOverflow instance; | ||
private final Map<Integer, User> users; | ||
private final Map<Integer, Question> questions; | ||
private final Map<String, List<Question>> taggedQuestions; | ||
private final Map<Integer, Answer> answers; | ||
private final Map<String, Tag> tags; | ||
|
||
private StackOverflow() { | ||
public StackOverflow() { | ||
users = new ConcurrentHashMap<>(); | ||
questions = new ConcurrentHashMap<>(); | ||
taggedQuestions = new ConcurrentHashMap<>(); | ||
answers = new ConcurrentHashMap<>(); | ||
tags = new ConcurrentHashMap<>(); | ||
} | ||
|
||
public static synchronized StackOverflow getInstance() { | ||
if (instance == null) { | ||
instance = new StackOverflow(); | ||
} | ||
return instance; | ||
} | ||
|
||
public void registerUser(User user) { | ||
users.put(user.getId(), user); | ||
public User createUser(String username, String email) { | ||
int id = users.size() + 1; | ||
User user = new User(id, username, email); | ||
users.put(id, user); | ||
return user; | ||
} | ||
|
||
public User loginUser(String username, String password) { | ||
for (User user : users.values()) { | ||
if (user.getUsername().equals(username) && user.getPassword().equals(password)) { | ||
return user; | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
public void postQuestion(Question question) { | ||
public Question askQuestion(User user, String title, String content, List<String> tags) { | ||
Question question = user.askQuestion(title, content, tags); | ||
questions.put(question.getId(), question); | ||
for (Tag tag : question.getTags()) { | ||
taggedQuestions.computeIfAbsent(tag.getName(), k -> new ArrayList<>()).add(question); | ||
this.tags.putIfAbsent(tag.getName(), tag); | ||
} | ||
return question; | ||
} | ||
|
||
public void postAnswer(Answer answer) { | ||
Question question = answer.getQuestion(); | ||
question.getAnswers().add(answer); | ||
public Answer answerQuestion(User user, Question question, String content) { | ||
Answer answer = user.answerQuestion(question, content); | ||
answers.put(answer.getId(), answer); | ||
return answer; | ||
} | ||
|
||
public void postComment(Comment comment) { | ||
// Add comment to the respective question or answer | ||
// ... | ||
public Comment addComment(User user, Commentable commentable, String content) { | ||
return user.addComment(commentable, content); | ||
} | ||
|
||
public void voteQuestion(Question question, int value) { | ||
synchronized (question) { | ||
question.setVoteCount(question.getVoteCount() + value); | ||
} | ||
updateUserReputation(question.getAuthor(), value); | ||
public void voteQuestion(User user, Question question, int value) { | ||
question.vote(user, value); | ||
} | ||
|
||
public void voteAnswer(Answer answer, int value) { | ||
synchronized (answer) { | ||
answer.setVoteCount(answer.getVoteCount() + value); | ||
} | ||
updateUserReputation(answer.getAuthor(), value); | ||
public void voteAnswer(User user, Answer answer, int value) { | ||
answer.vote(user, value); | ||
} | ||
|
||
private void updateUserReputation(User user, int value) { | ||
synchronized (user) { | ||
user.setReputation(user.getReputation() + value); | ||
} | ||
public void acceptAnswer(Answer answer) { | ||
answer.markAsAccepted(); | ||
} | ||
|
||
public List<Question> searchQuestions(String query) { | ||
List<Question> results = new ArrayList<>(); | ||
for (Question question : questions.values()) { | ||
if (question.getTitle().contains(query) || question.getBody().contains(query)) { | ||
results.add(question); | ||
} | ||
} | ||
return results; | ||
} | ||
|
||
public List<Question> getQuestionsByTag(String tagName) { | ||
return taggedQuestions.getOrDefault(tagName, new ArrayList<>()); | ||
return questions.values().stream() | ||
.filter(q -> q.getTitle().toLowerCase().contains(query.toLowerCase()) || | ||
q.getContent().toLowerCase().contains(query.toLowerCase()) || | ||
q.getTags().stream().anyMatch(t -> t.getName().equalsIgnoreCase(query))) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
public List<Question> getQuestionsByUser(User user) { | ||
List<Question> results = new ArrayList<>(); | ||
for (Question question : questions.values()) { | ||
if (question.getAuthor().equals(user)) { | ||
results.add(question); | ||
} | ||
} | ||
return results; | ||
return user.getQuestions(); | ||
} | ||
} | ||
|
||
// Getters | ||
public User getUser(int id) { return users.get(id); } | ||
public Question getQuestion(int id) { return questions.get(id); } | ||
public Answer getAnswer(int id) { return answers.get(id); } | ||
public Tag getTag(String name) { return tags.get(name); } | ||
} |
Oops, something went wrong.