mardi 20 décembre 2022

Implementing the decorator pattern in C#

i'm trying to implement the decorator pattern in C#. I'm creating a notification system that decorates the notification to be sent at runtime. I have this classes : `

namespace NotificationHub.Domain.Hubs
{
    public interface INotificationHub
    {
        public Task SendMessage(Notification notification);
    }
}

and it's implemented by 4 classes : BasicNotificationHub

namespace NotificationHub.Domain.Hubs
{
    public class BasicNotificationHub : INotificationHub
    {
        public async Task SendMessage(Notification notification)
        {
            await Task.FromResult(0);
            Console.WriteLine($"Basic Notification Behavior Called for {notification.ProductID}");
        }
    }
}

SignalR

   public class SignalRDecorator : INotificationHub
    {
        private readonly IHubContext<ProductNotificationHub, INotificationHub> _signalrNotificator;

        private readonly INotificationHub _notificationHub;

        public SignalRDecorator(IHubContext<ProductNotificationHub, INotificationHub> hubContext, INotificationHub notificationHub)
        {
            _signalrNotificator = hubContext;
            _notificationHub = notificationHub;
        }


        public async Task SendMessage(Notification notification)
        {
            await _notificationHub.SendMessage(notification);

            await _signalrNotificator.Clients.Group(notification.ProductID).SendMessage(notification);
        }
    }

SmsNotification

    public class SmsDecorator : INotificationHub
    {
        private readonly IUserService _userService;

        private readonly INotificationHub _notificationHub;

        public SmsDecorator(IUserService userService, INotificationHub notificationHub)
        {
            _userService = userService;
            _notificationHub = notificationHub;
        }

        public async Task SendMessage(Notification notification)
        {
            List<string> phoneNumbers = await _userService.GetUserPhonenNumbersSubscribedToProduct(notification.ProductID);

            await _notificationHub.SendMessage(notification);

            await SendMultipleSms(phoneNumbers, notification.ProductID, notification.ProductName);
        }

        private async Task SendMultipleSms(List<string> phoneNumbers, string productID, string productName)
        {
            foreach (string phoneNumber in phoneNumbers)
            {
                await SendSms(phoneNumber, productID, productName);
            }
        }

        private async Task SendSms(string phoneNumber, string productId, string productName)
        {
            await Task.FromResult(0);
            Console.WriteLine($"Sending Sms to {phoneNumber} about product {productId} {productName}");
        }
    }

And Mailing

    public class MailDecorator : INotificationHub
    {
        private readonly IUserService _userService;
        private readonly INotificationHub _notificationHub;

        public MailDecorator(IUserService userService, INotificationHub notificationHub)
        {
            _userService = userService;
            _notificationHub = notificationHub;
        }

        public async Task SendMessage(Notification notification)
        {
            List<string> mailsList = await _userService.GetUserMailsSubscribedToProduct(notification.ProductID);

            await _notificationHub.SendMessage(notification);

            await SendMultipleEmailAsync(mailsList, notification);
        }

        private async Task SendMultipleEmailAsync(List<string> mailsList, Notification notification)
        {

            foreach (string mailAdress in mailsList)
            {
                await SendEmailAsync(notification, mailAdress);
            }
        }

        private async Task SendEmailAsync(Notification notification, string mailAdress)
        {
            await Task.FromResult(0);
            Console.WriteLine($"Mail sent for product {notification.ProductID} to user {mailAdress}");
        }

    }

`

And the decoration happens in my service : `

    public class InMemoryProductService : IProductService
    {

        private readonly List<Product> _products;
        private IServiceProvider _serviceProvider;

        public InMemoryProductService(IServiceProvider serviceProvider)
        {
            _products = new List<Product>
            {
                new Product
                {
                    ProductId="P01",
                    ProductName="Cool Product",
                    Description="World coolest Product",
                    Price=9.99m,
                    Stock=10,
                    OnSale=false
                },
                new Product
                {
                    ProductId="P02",
                    ProductName="Cool Expensive Product",
                    Description="World coolest expensive Product",
                    Price=999.99m,
                    Stock=0,
                    OnSale=false
                }
            };

            _serviceProvider = serviceProvider;
        }

        public Task<List<Product>> GetProducts()
        {
            return Task.FromResult(_products);
        }

        public async Task UpdateProduct(Product product)
        {
            var foundProduct = _products.FirstOrDefault(x => x.ProductId == product.ProductId);

            if (foundProduct != null)
            {
                INotificationHub notificationHub = GetNotificationHubs(product, foundProduct);
                await notificationHub.SendMessage(new Notification
                {
                    ProductID = product.ProductId,
                    ProductName = product.ProductName,
                    Message = "i did it"
                });
            }
        }

        private INotificationHub GetNotificationHubs(Product product, Product foundProduct)
        {
            INotificationHub notificationHub = new BasicNotificationHub();

            if (product.Stock > foundProduct.Stock)
            {
                notificationHub = new SignalRDecorator((IHubContext<ProductNotificationHub, INotificationHub>)_serviceProvider.GetService(typeof(IHubContext<ProductNotificationHub, INotificationHub>)), notificationHub);
            }

            if (product.Price != foundProduct.Price)
            {
                notificationHub = new MailDecorator((IUserService)_serviceProvider.GetService(typeof(IUserService)), notificationHub);
            }

            if (product.OnSale != foundProduct.OnSale)
            {
                notificationHub = new SmsDecorator((IUserService)_serviceProvider.GetService(typeof(IUserService)), notificationHub);
            }

            return notificationHub;
        }
    }

`

Is this a good way to do it ? I'm doubting the part where i return the INotificationHub i don't like the fact that i call _serviceProvider.GetService().

If this is not good do you have any suggestions ?

Aucun commentaire:

Enregistrer un commentaire