-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathmailService.java
104 lines (88 loc) · 4.63 KB
/
mailService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
Решение задачи MailService.
// MailMessage и Salary имеют практически идентичный интерфейс
// за исключением типа поля content. Давайте абстрагируем это знание в интерфейс.
public static interface Sendable<T> {
String getFrom();
String getTo();
T getContent();
}
// Абстрагируем логику хранения всех элементов класса во внутренних полях класса,
// создав класс SimpleSendable. Не забудем указать реализуемый интерфейс.
public static class SimpleSendable<T> implements Sendable<T> {
private String from, to;
private T content;
public SimpleSendable(String from, String to, T content) {
this.from = from;
this.to = to;
this.content = content;
}
@Override
public String getFrom() {
return from;
}
@Override
public String getTo() {
return to;
}
@Override
public T getContent() {
return content;
}
}
// Теперь объявим MailMessage и Salary, отнаследовавшись от SimpleSendable
// с конкретным параметром типа.
public static class MailMessage extends SimpleSendable<String> {
public MailMessage(String from, String to, String content) {
super(from, to, content);
}
}
public static class Salary extends SimpleSendable<Integer> {
public Salary(String from, String to, Integer content) {
super(from, to, content);
}
}
// forEachOrdered и forEach ожидают в качестве аргумента класс,
// реализующий интерфейс Consumer.
// Судя по исходному коду, Consumer потребляет письма с содержимым,
// соответствующим параметру класса MailService.
public static class MailService<T> implements Consumer<Sendable<T>> {
// Если внимательно посмотреть на исходный код задания, можно заметить,
// что логика метода get у получаемого в getMailBox Map'а при отсутствующем элементе
// отличается от логики стандартных коллекций. Переназначим эту логику в анонимном
// наследнике HashMap.
private Map<String, List<T>> messagesMap = new HashMap<String, List<T>>(){
@Override
public List<T> get(Object key) {
if (this.containsKey(key)) {
// Возвращать изменяемый список во внешний мир – не очень хорошая идея
// по причине того, что его изменение может испортить внутреннее состояние
// словаря. Лучше оборачивать подобный вывод в
// Collections.unmodifiableList.
// Однако здесь мы не можем так поступить по причине того,
// что добавлять новые элементы в списки из accept будет неудобно.
// Нужно реализовать дополнительный метод getMutable, который возвращал
// бы изменяемый список, удобный для модификации.
// Но добавить новый метод мы можем только в именованный класс.
return super.get(key);
} else {
// Collections.emptyList() возвращает один и тот же экземпляр
// неизменяемого списка. Если бы мы возвращали здесь, допустим,
// new ArrayList<>(), то множество вызовов get по отсутвующему
// элементу создавало бы множество лишних объектов.
return Collections.emptyList();
}
}
};
@Override
public void accept(Sendable<T> sendable) {
List<T> ts = messagesMap.get(sendable.getTo());
if (ts.size() == 0) {
ts = new ArrayList<>();
}
ts.add(sendable.getContent());
messagesMap.put(sendable.getTo(), ts);
}
public Map<String, List<T>> getMailBox() {
return messagesMap;
}
}