• 在抽象工厂中使用依赖倒置


    本篇实现的效果为:当学校有通知的时候,把通知内容发送到每一个人,如下:

    1


    □ 思路
    可以把通知内容、通知对象、通知方式、通知行为抽象成类、接口、接口实现,再为一些接口创建对应的抽象工厂及其实现。所有的这些依赖可以通过"依赖倒置容器"来管理。

    →关于通知内容,可以封装成一个类
    →关于通知对象,可以抽象出基类和实现类
    →关于通知对象的Repository,有对应的接口、接口实现,抽象工厂、抽象工厂实现
    →关于Email通知方式的Repository,有对应的接口,接口实现,抽象工厂、抽象工厂实现
    →关于通知的行为,可以有对应的接口和接口实现
    →关于客户端调用,这么些接口和接口实现,以及抽象工厂和抽象工厂实现,我们需要使用"依赖倒置",把所有的依赖注册到依赖倒置容器中,使用的时候,再分别拿出来。

    另外,可以为所有的抽象工厂提供一个统一的访问入口,让一个接口实现所有的抽象工厂接口,外部访问的时候,可以通过这个接口拿到所有的抽象工厂。


    □ 关于通知内容

    可以把通知的对象抽象出一个基类来,学生、老师等继承于这个基类。

    using System;
    
    namespace AbstractFactoryDI.Core.Model
    {
        public abstract class Person
        {
            public virtual Guid Id { get; set; }
            public virtual string PIN { get; set; }
            public virtual string Name { get; set; }
            public virtual string Surname { get; set; }
            public virtual string Email { get; set; }
        }
    
        public partial class Student : Person
        {         
        }
    
        public partial class Trainer : Person
        {         
        }
    }


    □ 关于通知对象的Repository

    关于通知对象Person的Repository接口,从中可以获取到通知对象Person的集合。

    using System.Collections.Generic;
    using AbstractFactoryDI.Core.Model;
    
    namespace AbstractFactoryDI.Core.Repository
    {
        public interface IPersonRepository
        {
            IEnumerable<Person> GetAllActivePeople();
        }
    }

    为通知对象Person的Repository接口创建抽象工厂。

    using AbstractFactoryDI.Core.Repository;
    
    namespace AbstractFactoryDI.Core.Factories
    {
        public interface IRepositoryFactory
        {
            IPersonRepository CreatePersonRepository();
        }
    }

    针对IPersonRepository的实现是:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using AbstractFactoryDI.Core.Model;
    using AbstractFactoryDI.Core.Repository;
    
    namespace AbstractFactoryDI.Infrastructure.Repository
    {
        public class PersonRepository : IPersonRepository
        {
            private static ICollection<Person>  _people = new List<Person>()
            {
                new Student(){Id = Guid.NewGuid(),Name = "jack", Surname = "cute jack",Email = "jack@sina.com", PIN = "001"},
                new Student(){Id = Guid.NewGuid(),Name = "sunny", Surname = "cute sunny",Email = "sunny@sina.com", PIN = "002"},
            };
            public System.Collections.Generic.IEnumerable<Core.Model.Person> GetAllActivePeople()
            {
                return _people.AsEnumerable();
            }
        }
    }

    □ 关于通知方式中的Email通知

    把通过Email通知的方式也抽象成一个接口。

    using System;
    
    namespace AbstractFactoryDI.Core.Notificators
    {
        public interface IEmailNotificator : IDisposable
        {
            void SendNotification(string toAddress, string message);
        }
    }

    与IEmailNotificator对应的抽象工厂为:

    using AbstractFactoryDI.Core.Notificators;
    
    namespace AbstractFactoryDI.Core.Factories
    {
        public interface IEmailNotificatorFactory
        {
            IEmailNotificator CreateEmailNotificator();
        }
    }

    IEmailNotificator接口实现是:

    using System;
    using AbstractFactoryDI.Core.Notificators;
    
    namespace AbstractFactoryDI.Infrastructure.Notificators
    {
        public class EmailNotificator : IEmailNotificator
        {
    
            public void SendNotification(string toAddress, string message)
            {
                //System.Net.Mail.SmtpClient发邮件
                Console.WriteLine(message);
                Console.WriteLine();
                Console.WriteLine();
            }
    
            public void Dispose()
            {
                //dispose System.Net.Mail.SmtpClient
            }
        }
    }

    □ 关于抽象工厂的统一入口

    现在已经有了有关通知对象的抽象工厂IRepositoryFactory和有关邮件通知方式的抽象工厂IEmailNotificatorFactory,我们还希望为所有的这些抽象工厂创建一个统一的访问入口,于是创建实现所有抽象工厂接口的接口:

    namespace AbstractFactoryDI.Core.Factories
    {
        public interface IServiceFactory : IRepositoryFactory, IEmailNotificatorFactory
        {
             
        }
    }

    IServiceFactory对应的实现是:

    using AbstractFactoryDI.Core.Factories;
    using AbstractFactoryDI.Infrastructure.Notificators;
    using AbstractFactoryDI.Infrastructure.Repository;
    
    namespace AbstractFactoryDI.Factories.Concrete
    {
        public class ServiceFactory : IServiceFactory
        {
    
            public virtual Core.Repository.IPersonRepository CreatePersonRepository()
            {
                return new PersonRepository();
            }
    
            public virtual Core.Notificators.IEmailNotificator CreateEmailNotificator()
            {
                return new EmailNotificator();
            }
        }
    }

    □ 关于通知内容

    通知内容包含放假开始时间、结束时间、内容等,把之封装成一个类。

    using System;
    
    namespace AbstractFactoryDI.Core.Services
    {
        public class ClosureInfo
        {
            public DateTime StartDate { get; set; }
            public DateTime EndDate { get; set; }
            public string Reason { get; set; }
        }
    }

    □ 关于通知行为

    发送通知需要以上的ClosureInfo类型参数,考虑到发送通知的方式可能有多种,比如短信、邮件等,可以为发送通知抽象出一个接口。

    namespace AbstractFactoryDI.Core.Services
    {
        public interface INotificationService
        {
            void NotifySchoolClosure(ClosureInfo info);
        }
    }


    关于INotificationService的实现。我们可以从抽象工厂统一入口拿到IPersonRepository,从而获取到所有的通知对象。还可以从抽象工厂统一入口拿到IEmailNotificator,来发送通知信息。

    using System.Collections.Generic;
    using System.Text;
    using AbstractFactoryDI.Core.Factories;
    using AbstractFactoryDI.Core.Model;
    
    namespace AbstractFactoryDI.Core.Services
    {
        public class NotificationService : INotificationService
        {
            private readonly IServiceFactory _factory;
    
            public NotificationService(IServiceFactory factory)
            {
                _factory = factory;
            }
            public void NotifySchoolClosure(ClosureInfo info)
            {
                var personRepository = _factory.CreatePersonRepository();
                var people = personRepository.GetAllActivePeople();
                NotifySchoolClosure(info, people);
            }
    
            private void NotifySchoolClosure(ClosureInfo info, IEnumerable<Person> people)
            {
                using (var notificator = _factory.CreateEmailNotificator())
                {
                    foreach (var person in people)
                    {
                        notificator.SendNotification(person.Email, FormatMessage(person, info));
                    }
                }
            }
    
            private string FormatMessage(Person person, ClosureInfo info)
            {
                var str = new StringBuilder();
                str.Append(string.Format("您好 {0}
    ", person.Name));
                str.Append(info.Reason);
                str.Append(string.Format(" 学校将在{0}和{1}期间放假
    ", info.StartDate, info.EndDate));
                str.Append("请注意安全~~");
                return str.ToString();
            }
        }
    }

     

    □ 客户端

    前面已经有了抽象工厂以及抽象工厂的实现,抽象工厂入口以及抽象工厂入口的实现,接口和接口实现......所有的这些,都可以让依赖倒置来解决,这里使用Microsoft.Practices.Unity。

    using AbstractFactoryDI.Core.Factories;
    using AbstractFactoryDI.Core.Services;
    using AbstractFactoryDI.Factories.Concrete;
    using Microsoft.Practices.Unity;
    
    namespace AbstractFactoryDI.Client
    {
        public class RootContainer
        {
            private static readonly UnityContainer _container;
    
            static RootContainer()
            {
                _container = new UnityContainer();
                RegisterAll();
            }
    
            internal static void RegisterAll()
            {
                _container.RegisterType<IEmailNotificatorFactory, ServiceFactory>();
                _container.RegisterType<IRepositoryFactory, ServiceFactory>();
                _container.RegisterType<IServiceFactory, ServiceFactory>();
                _container.RegisterType<INotificationService, NotificationService>();
            }
    
            internal static Iofs Resolve<Iofs>()
            {
                return _container.Resolve<Iofs>();
            }
        }
    }

    客户端调用的时候,首先在构造函数中注册所有的依赖,然后在使用的时候,在从依赖倒置容器中解析出具体的接口实现。

    using System;
    using AbstractFactoryDI.Core.Services;
    
    namespace AbstractFactoryDI.Client
    {
        class Program
        {
            public Program()
            {
                RootContainer.RegisterAll();
            }
    
            static void Main(string[] args)
            {
                NotifyChristmasVacation();
                Console.ReadKey();
            }
    
            static void NotifyChristmasVacation()
            {
                INotificationService notificaitonService = RootContainer.Resolve<INotificationService>();
                var closureInfo = new ClosureInfo()
                {
                    StartDate = new DateTime(DateTime.Now.Year, 12, 24),
                    EndDate = new DateTime(DateTime.Now.Year, 12, 26),
                    Reason = "圣诞节放假~~"
                };
                notificaitonService.NotifySchoolClosure(closureInfo);
            }
        }
    }

    参考资料:

    Dependency Injection of an Abstract Factory

  • 相关阅读:
    HTTP/2的优先级
    JavaScript 日期权威指南
    岂曰无衣与子同袍
    Android项目中实现native调用
    关键渲染路径
    @ModelAttribute使用详解
    @SessionAttribute使用详解
    @ControllerAdvice 拦截异常并统一处理
    js获取文件MD5值
    Mybatis分页插件PageHelper的配置和使用方法
  • 原文地址:https://www.cnblogs.com/darrenji/p/3762119.html
Copyright © 2020-2023  润新知