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

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

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

原文地址:https://www.cnblogs.com/darrenji/p/3762119.html