-
Notifications
You must be signed in to change notification settings - Fork 31
/
Mediator.cs
148 lines (123 loc) · 4.96 KB
/
Mediator.cs
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
namespace DesignPatterns.Behavioral;
public class Mediator
{
[Fact]
public void Execute()
{
IParcelService mediator = new ParcelService();
IPostalUser company = new RejectingParcelUser("12345", mediator);
var customer = new AcceptingParcelUser("54231", mediator);
mediator.Register(company);
mediator.Register(customer);
var parcel1 = new Parcel();
company.SendParcel("54231", parcel1);
// The destination exists, the customer receives the parcel.
Assert.Contains(parcel1, customer.ParcelsReceived);
var parcel2 = new Parcel();
customer.SendParcel("99999", parcel2);
// The destination doesn't exists, the customer got it back.
Assert.Contains(parcel2, customer.ParcelsReceived);
var parcel3 = new Parcel();
customer.SendParcel("12345", parcel3);
// The destination is not accepting parcels, the customer got it back again.
Assert.Contains(parcel3, customer.ParcelsReceived);
}
/// <summary>
/// Mediator
/// </summary>
/// <remarks>
/// Defines the interface for communication between <see cref="IPostalUser">Colleague</see> objects.
/// </remarks>
public interface IParcelService
{
void Register(IPostalUser postalUser);
void Send(IPostalUser fromPostalUser, string toPostalCode, Parcel parcel);
}
/// <summary>
/// Colleague
/// </summary>
/// <remarks>
/// Defines the interface for communication with other <see cref="IPostalUser">Colleagues</see> through its
/// <see cref="IParcelService">Mediator</see>.
/// </remarks>
public interface IPostalUser
{
string PostalCode { get; }
void ReceiveParcel(string fromPostalCode, Parcel parcel);
void SendParcel(string toPostalCode, Parcel parcel);
}
public class Parcel;
/// <summary>
/// Concrete Mediator
/// </summary>
/// <remarks>
/// Implements the Mediator interface and coordinates communication between <see cref="IPostalUser">Colleague</see>
/// objects.
/// It is aware of all of the <see cref="IPostalUser">Colleagues</see> and their purposes with regards to
/// inter-communication.
/// </remarks>
public class ParcelService : IParcelService
{
private readonly Dictionary<string, IPostalUser> _usersByPostalCode = [];
public void Register(IPostalUser postalUser)
{
ArgumentNullException.ThrowIfNull(postalUser);
_usersByPostalCode.TryAdd(postalUser.PostalCode, postalUser);
}
public void Send(IPostalUser fromPostalUser, string toPostalCode, Parcel parcel)
{
ArgumentNullException.ThrowIfNull(fromPostalUser);
if (_usersByPostalCode.TryGetValue(toPostalCode, out IPostalUser toPostalUser))
{
toPostalUser.ReceiveParcel(fromPostalUser.PostalCode, parcel);
}
// Make sure the sender is not rejecting parcels, otherwise we may end up with an infinite callback.
else if (fromPostalUser is not RejectingParcelUser)
{
// Send it back, we couldn't find the recipient
fromPostalUser.ReceiveParcel(toPostalCode, parcel);
}
}
}
/// <summary>
/// Concrete Colleague
/// </summary>
/// <remarks>
/// Implements the <see cref="IPostalUser">Colleague</see> interface and
/// communicates with other <see cref="IPostalUser">Colleagues</see> through its <see cref="IParcelService">Mediator</see>.
/// </remarks>
public class RejectingParcelUser(string postalCode, IParcelService parcelService) : IPostalUser
{
public string PostalCode { get; } = postalCode;
public void ReceiveParcel(string fromPostalCode, Parcel parcel)
{
// Rejects all deliveries, send it back.
parcelService.Send(this, fromPostalCode, parcel);
}
public void SendParcel(string toPostalCode, Parcel parcel)
{
parcelService.Send(this, toPostalCode, parcel);
}
}
/// <summary>
/// Concrete Colleague
/// </summary>
/// <remarks>
/// Implements the <see cref="IPostalUser">Colleague</see> interface and
/// communicates with other <see cref="IPostalUser">Colleagues</see> through its <see cref="IParcelService">Mediator</see>.
/// </remarks>
public class AcceptingParcelUser(string postalCode, IParcelService parcelService) : IPostalUser
{
private readonly List<Parcel> _parcelsReceived = [];
public IReadOnlyList<Parcel> ParcelsReceived => _parcelsReceived.AsReadOnly();
public string PostalCode => postalCode;
public void ReceiveParcel(string fromPostalCode, Parcel parcel)
{
_parcelsReceived.Add(parcel);
}
public void SendParcel(string toPostalCode, Parcel parcel)
{
parcelService.Send(this, toPostalCode, parcel);
}
}
}