Skip to content

Commit

Permalink
refactor: 重構 Usecase,將查改進行分離
Browse files Browse the repository at this point in the history
  • Loading branch information
aa89227 committed Jan 28, 2024
1 parent 01aceee commit 8517d3b
Show file tree
Hide file tree
Showing 31 changed files with 90 additions and 94 deletions.
8 changes: 8 additions & 0 deletions Application/Common/IRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ public interface IRepository
public string Save(Monopoly monopoly);
}

public interface ICommandRepository : IRepository
{
}

public interface IQueryRepository : IRepository
{
}

internal static class RepositoryExtensions
{
internal static string Save(this IRepository repository, Domain.Monopoly domainMonopoly)
Expand Down
8 changes: 0 additions & 8 deletions Application/Common/QueryUsecase.cs

This file was deleted.

20 changes: 17 additions & 3 deletions Application/Common/Usecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,24 @@

namespace Application.Common;

public abstract class Usecase<TRequest, TResponse>(IRepository repository)
public abstract class Usecase<TRequest, TResponse>()
where TRequest : Request where TResponse : Response
{
protected IRepository Repository { get; } = repository;
public abstract Task ExecuteAsync(TRequest request, IPresenter<TResponse> presenter);
}

public abstract class CommandUsecase<TRequest, TResponse>(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: Usecase<TRequest, TResponse>()
where TRequest : Request where TResponse : Response
{
protected ICommandRepository Repository { get; } = repository;
protected IEventBus<DomainEvent> EventBus { get; } = eventBus;
}

public abstract class QueryUsecase<TRequest, TResponse>(ICommandRepository repository)
where TRequest : Request
{
protected ICommandRepository Repository { get; } = repository;

public abstract Task ExecuteAsync(TRequest request, IPresenter<TResponse> presenter);
}
}
4 changes: 2 additions & 2 deletions Application/DependencyInjection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ private static IServiceCollection AddUseCases(this IServiceCollection services)
{
var assembly = typeof(DependencyInjection).Assembly;
var types = assembly.GetTypes();
var useCaseType = typeof(Usecase<,>);
var useCaseType = typeof(CommandUsecase<,>);
var queryUsecaseType = typeof(QueryUsecase<,>);

foreach (var type in types.Where(t => t.BaseType?.IsGenericType is true))
foreach (var type in types.Where(t => t.BaseType?.IsGenericType is true && t.IsAbstract == false))
{
if (type.BaseType?.GetGenericTypeDefinition() == useCaseType)
{
Expand Down
7 changes: 2 additions & 5 deletions Application/Queries/GetReadyInfoUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,9 @@ public record ReadyInfo(Player[] Players, string HostId);
public record Player(string PlayerId, bool IsReady, string? RoleId, int? LocationId);
}

public class GetReadyInfoUsecase : QueryUsecase<GetReadyInfoRequest, GetReadyInfoResponse>
public class GetReadyInfoUsecase(ICommandRepository repository)
: QueryUsecase<GetReadyInfoRequest, GetReadyInfoResponse>(repository)
{
public GetReadyInfoUsecase(IRepository repository) : base(repository)
{
}

public override async Task ExecuteAsync(GetReadyInfoRequest request, IPresenter<GetReadyInfoResponse> presenter)
{
var game = Repository.FindGameById(request.GameId);
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/BidUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record BidRequest(string GameId, string PlayerId, decimal BidPrice)

public record BidResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class BidUsecase(IRepository repository)
: Usecase<BidRequest, BidResponse>(repository)
public class BidUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<BidRequest, BidResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(BidRequest request, IPresenter<BidResponse> presenter)
{
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/BuildHouseUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record BuildHouseRequest(string GameId, string PlayerId)

public record BuildHouseResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class BuildHouseUsecase(IRepository repository)
: Usecase<BuildHouseRequest, BuildHouseResponse>(repository)
public class BuildHouseUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<BuildHouseRequest, BuildHouseResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(BuildHouseRequest request, IPresenter<BuildHouseResponse> presenter)
{
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/ChooseDirectionUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record ChooseDirectionRequest(string GameId, string PlayerId, string Dire

public record ChooseDirectionResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class ChooseDirectionUsecase(IRepository repository)
: Usecase<ChooseDirectionRequest, ChooseDirectionResponse>(repository)
public class ChooseDirectionUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<ChooseDirectionRequest, ChooseDirectionResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(ChooseDirectionRequest request, IPresenter<ChooseDirectionResponse> presenter)
{
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/CreateGameUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ public record CreateGameRequest(string HostId, string[] PlayerIds) : Request(nul

public record CreateGameResponse(string GameId) : Response;

public class CreateGameUsecase(IRepository repository)
: Usecase<CreateGameRequest, CreateGameResponse>(repository)
public class CreateGameUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<CreateGameRequest, CreateGameResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(CreateGameRequest request, IPresenter<CreateGameResponse> presenter)
{
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/EndAuctionUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record EndAuctionRequest(string GameId, string PlayerId)

public record EndAuctionResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class EndAuctionUsecase(IRepository repository)
: Usecase<EndAuctionRequest, EndAuctionResponse>(repository)
public class EndAuctionUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<EndAuctionRequest, EndAuctionResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(EndAuctionRequest request, IPresenter<EndAuctionResponse> presenter)
{
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/EndRoundUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record EndRoundRequest(string GameId, string PlayerId)

public record EndRoundResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class EndRoundUsecase(IRepository repository)
: Usecase<EndRoundRequest, EndRoundResponse>(repository)
public class EndRoundUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<EndRoundRequest, EndRoundResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(EndRoundRequest request, IPresenter<EndRoundResponse> presenter)
{
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/GameStartUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record GameStartRequest(string GameId, string PlayerId)

public record GameStartResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class GameStartUsecase(IRepository repository)
: Usecase<GameStartRequest, GameStartResponse>(repository)
public class GameStartUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<GameStartRequest, GameStartResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(GameStartRequest request, IPresenter<GameStartResponse> presenter)
{
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/MortgageUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record MortgageRequest(string GameId, string PlayerId, string BlockId)

public record MortgageResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class MortgageUsecase(IRepository repository)
: Usecase<MortgageRequest, MortgageResponse>(repository)
public class MortgageUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<MortgageRequest, MortgageResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(MortgageRequest request, IPresenter<MortgageResponse> presenter)
{
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/PayTollUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record PayTollRequest(string GameId, string PlayerId)

public record PayTollResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class PayTollUsecase(IRepository repository)
: Usecase<PayTollRequest, PayTollResponse>(repository)
public class PayTollUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<PayTollRequest, PayTollResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(PayTollRequest request, IPresenter<PayTollResponse> presenter)
{
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/PlayerBuyLandUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record PlayerBuyLandRequest(string GameId, string PlayerId, string LandID

public record PlayerBuyLandResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class PlayerBuyLandUsecase(IRepository repository)
: Usecase<PlayerBuyLandRequest, PlayerBuyLandResponse>(repository)
public class PlayerBuyLandUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<PlayerBuyLandRequest, PlayerBuyLandResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(PlayerBuyLandRequest request, IPresenter<PlayerBuyLandResponse> presenter)
{
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/PlayerPreparedUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record PlayerPreparedRequest(string GameId, string PlayerId)

public record PlayerPreparedResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class PlayerPreparedUsecase(IRepository repository)
: Usecase<PlayerPreparedRequest, PlayerPreparedResponse>(repository)
public class PlayerPreparedUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<PlayerPreparedRequest, PlayerPreparedResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(PlayerPreparedRequest request, IPresenter<PlayerPreparedResponse> presenter)
{
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/PlayerRollDiceUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record PlayerRollDiceRequest(string GameId, string PlayerId)

public record PlayerRollDiceResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class PlayerRollDiceUsecase(IRepository repository)
: Usecase<PlayerRollDiceRequest, PlayerRollDiceResponse>(repository)
public class PlayerRollDiceUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<PlayerRollDiceRequest, PlayerRollDiceResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(PlayerRollDiceRequest request, IPresenter<PlayerRollDiceResponse> presenter)
{
Expand Down
3 changes: 2 additions & 1 deletion Application/Usecases/RedeemUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ public record RedeemRequest(string GameId, string PlayerId, string BlockId)

public record RedeemResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class RedeemUsecase(IRepository repository) : Usecase<RedeemRequest, RedeemResponse>(repository)
public class RedeemUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<RedeemRequest, RedeemResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(RedeemRequest request, IPresenter<RedeemResponse> presenter)
{
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/SelectRoleUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record SelectRoleRequest(string GameId, string PlayerId, string roleId)

public record SelectRoleResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class SelectRoleUsecase(IRepository repository)
: Usecase<SelectRoleRequest, SelectRoleResponse>(repository)
public class SelectRoleUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<SelectRoleRequest, SelectRoleResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(SelectRoleRequest request, IPresenter<SelectRoleResponse> presenter)
{
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/SelectRoomLocationUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record SelectLocationRequest(string GameId, string PlayerId, int Location

public record SelectLocationResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class SelectLocationUsecase(IRepository repository)
: Usecase<SelectLocationRequest, SelectLocationResponse>(repository)
public class SelectLocationUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<SelectLocationRequest, SelectLocationResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(SelectLocationRequest request, IPresenter<SelectLocationResponse> presenter)
{
Expand Down
4 changes: 2 additions & 2 deletions Application/Usecases/SettlementUsecase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record SettlementRequest(string GameId, string PlayerId)

public record SettlementResponse(IReadOnlyList<DomainEvent> Events) : CommandResponse(Events);

public class SettlementUsecase(IRepository repository)
: Usecase<SettlementRequest, SettlementResponse>(repository)
public class SettlementUsecase(ICommandRepository repository, IEventBus<DomainEvent> eventBus)
: CommandUsecase<SettlementRequest, SettlementResponse>(repository, eventBus)
{
public override async Task ExecuteAsync(SettlementRequest request, IPresenter<SettlementResponse> presenter)
{
Expand Down
8 changes: 0 additions & 8 deletions Client/Pages/TypedHubConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,16 @@ internal class TypedHubConnection
{
private readonly HubConnection hubConnection;

public event PlayerJoinGameEventDelegate? PlayerJoinGameEventHandler;
public delegate void PlayerJoinGameEventDelegate(PlayerJoinGameEvent e);
public event GetReadyInfoEventDelegate? GetReadyInfoEventHandler;
public delegate void GetReadyInfoEventDelegate(GetReadyInfoEventArgs e);
public event WelcomeEventDelegate? WelcomeEventHandler;
public delegate void WelcomeEventDelegate(WelcomeEventArgs e);

public TypedHubConnection(HubConnection hubConnection)
{
hubConnection.On<PlayerJoinGameEvent>(nameof(PlayerJoinGameEvent), (e) => PlayerJoinGameEventHandler?.Invoke(e));
hubConnection.On<GetReadyInfoEventArgs>("GetReadyInfoEvent", (e) => GetReadyInfoEventHandler?.Invoke(e));
hubConnection.On<WelcomeEventArgs>("WelcomeEvent", (e) => WelcomeEventHandler?.Invoke(e));
this.hubConnection = hubConnection;
}
public async Task GetReadyInfo() => await hubConnection.SendAsync("GetReadyInfo");
}

internal class PlayerJoinGameEvent : EventArgs
{
public required string PlayerId { get; set; }
}
11 changes: 6 additions & 5 deletions Server/DependencyInjection.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
using System.Reflection;
using Application.Common;
using Application.Common;
using Domain.Common;
using Server.Common;
using Server.Hubs;
using Server.Presenters;
using Server.Repositories;
using System.Reflection;

namespace Server;

public static class DependencyInjection
{
public static IServiceCollection AddMonopolyServer(this IServiceCollection services)
{
services.AddSingleton<IRepository, InMemoryRepository>()
var repository = new InMemoryRepository();
services.AddSingleton<ICommandRepository>(repository)
.AddSingleton<IQueryRepository>(repository)
.AddSingleton<IEventBus<DomainEvent>, MonopolyEventBus>()
.AddTransient(typeof(SignalrDefaultPresenter<>), typeof(SignalrDefaultPresenter<>));
services.AddSignalREventHandlers();
Expand All @@ -22,7 +23,7 @@ public static IServiceCollection AddMonopolyServer(this IServiceCollection servi
private static IServiceCollection AddSignalREventHandlers(this IServiceCollection services)
{
var handlers = Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t is { IsClass: true, IsAbstract: false }
.Where(t => t is { IsClass: true, IsAbstract: false }
&& t.IsAssignableTo(typeof(IMonopolyEventHandler)))
.ToList();
foreach (var handler in handlers)
Expand Down
6 changes: 3 additions & 3 deletions Server/Hubs/MonopolyHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
using Microsoft.AspNetCore.SignalR;
using Server.Presenters;
using SharedLibrary;
using System.Security.Claims;
using SharedLibrary.ResponseArgs.Monopoly;
using SharedLibrary.ResponseArgs.ReadyRoom;
using System.Security.Claims;

namespace Server.Hubs;

[Authorize]
public class MonopolyHub(IRepository repository) : Hub<IMonopolyResponses>
public class MonopolyHub(ICommandRepository repository) : Hub<IMonopolyResponses>
{
private const string Playerid = "PlayerId";
private const string Gameid = "GameId";
Expand All @@ -38,7 +38,7 @@ await usecase.ExecuteAsync(
public async Task PlayerBuyLand(string gameId, string userId, string blockId, PlayerBuyLandUsecase usecase, SignalrDefaultPresenter<PlayerBuyLandResponse> presenter)
{
await usecase.ExecuteAsync(
new PlayerBuyLandRequest(gameId, userId, blockId),
new PlayerBuyLandRequest(gameId, userId, blockId),
presenter
);
}
Expand Down
9 changes: 2 additions & 7 deletions Server/MonopolyEventBus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@

namespace Server;

internal class MonopolyEventBus : IEventBus<DomainEvent>
internal class MonopolyEventBus(IEnumerable<IMonopolyEventHandler> handlers) : IEventBus<DomainEvent>
{
private readonly Dictionary<Type, IMonopolyEventHandler> _handlers;
private readonly Dictionary<Type, IMonopolyEventHandler> _handlers = handlers.ToDictionary(h => h.EventType, h => h);

public MonopolyEventBus(IEnumerable<IMonopolyEventHandler> handlers)
{
_handlers = handlers.ToDictionary(h => h.EventType, h => h);
}

public async Task PublishAsync(IEnumerable<DomainEvent> events)
{
foreach (var e in events)
Expand Down
2 changes: 1 addition & 1 deletion Server/Repositories/InMemoryRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Server.Repositories;

public class InMemoryRepository : IRepository
public class InMemoryRepository : ICommandRepository, IQueryRepository
{
private readonly Dictionary<string, Monopoly> Games = new();

Expand Down
2 changes: 1 addition & 1 deletion Test/ServerTests/AcceptanceTests/CreateGameTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public void Setup()
{
server = new MonopolyTestServer();
jwtTokenService = server.GetRequiredService<MockJwtTokenService>();
repository = server.GetRequiredService<IRepository>();
repository = server.GetRequiredService<IQueryRepository>();
jwtBearerOptions = server.GetRequiredService<IOptionsMonitor<JwtBearerOptions>>().Get("Bearer");
}

Expand Down
4 changes: 2 additions & 2 deletions Test/ServerTests/AcceptanceTests/PlayerJoinGameTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
using Microsoft.Extensions.Options;
using Server.DataModels;
using SharedLibrary;
using SharedLibrary.ResponseArgs.Monopoly;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using SharedLibrary.ResponseArgs.Monopoly;

namespace ServerTests.AcceptanceTests;

Expand All @@ -22,7 +22,7 @@ public void Setup()
{
server = new MonopolyTestServer();
jwtTokenService = server.GetRequiredService<MockJwtTokenService>();
repository = server.GetRequiredService<IRepository>();
repository = server.GetRequiredService<IQueryRepository>();
jwtBearerOptions = server.GetRequiredService<IOptionsMonitor<JwtBearerOptions>>().Get("Bearer");
}

Expand Down
Loading

0 comments on commit 8517d3b

Please sign in to comment.