Skip to content

Latest commit

 

History

History
151 lines (106 loc) · 3.77 KB

File metadata and controls

151 lines (106 loc) · 3.77 KB

Day-28 想要做什麼東西,蓋工廠就對了


接著設計兩個 Logging 與 Error

基於以上兩個都屬於需要 Handle 的功能,所以這裡宣告一個IHandler即可

    public interface IHandler<T>
    {
        void Handle(Action<T> handler);
    }

用法大概像是這樣

    public class Handler<T> : IHandler<T>
    {
        private readonly Action<T> _handler;

        public Handler(Action<T> handler)
        {
            _handler = handler;
        }

        public void Handle(T context)
            => _handler(context);
    }

這樣似乎不夠,還需要一個可以取得這些功能的方法

System.IServiceProvider是透過 Type 提供指定服務物件的內建interface

所以先透過它來取用所需要的指定Handler類型

    public interface IHandler
    {
        void Handle<T>(T context);
    }

    public class Handler : IHandler
    {
        private readonly IServiceProvider _provider;

        public Handler(IServiceProvider provider)
        {
            _provider = provider;
        }
        public void Handle<T>(T context)
            => _provider.GetService<IHandler<T>>()
                .Each(handler => handler.Handle(context));
    }

因為需要將IHandler注入到Chain中,所以需要一個建立Chain的方法

    public class ChainFactory : IChainFactory
    {
        private readonly IHandler _handler;

        public ChainFactory(IHandler handler)
        {
            _handler = handler;
        }

        public IChain<T> Create<T>(Func<T> func)
        {
            return new LazyChain<T>(factory);
        }

        public IChainAwaiter<T> Create<T>(Task<T> task)
        {
            return new ChainAwaiter<T>(task);
        }
    }

當然作為起始方法的類別也得轉為普通可建構的物件才能注入IHandler

    public class Chain
    {
        private readonly IChainFactory _factory;

        public Chain(IChainFactory factory)
        {
            _factory = factory;
        }

        public IChain<T> StartBy<T>(T current)
            => new LazyChain<T>(_factory,current);

        public IChainAwaiter<T> StartBy<T>(Task<T> task)
            => new ChainAwaiter<T>(_factory,task);
    }

最後這次就偷懶仰賴一下 DI 來幫我們把剩下的做完吧

這次以 Microsoft.Extensions.DependencyInjection 作為 DI Container

同場佳映 Crawler 也放進去吧

    public static class ServiceCollectionExtensions
    {
        public static ChainBuilder AddChain(this IServiceCollection services)
        {
            services.AddTransient<Chain>()
                .AddTransient<IChainFactory, ChainFactory>()
                .AddSingleton<IHandler, Handler>();
            return new ChainBuilder(services);
        }

        public static IServiceCollection AddCrawler(this IServiceCollection services)
            => services.AddChain()
                .AddTransient<IHttpClient,DefaultHttpClient>()
                .AddTransient<IHtmlLoader, DefaultHtmlLoader>()
                .AddTransient<ICrawler, Crawler>();
    }

如此一來,注入的準備就可以算是準備完成

上述的程式目的在於,將我們期望的 Handler 能夠注入 Chain 的功能內

再透過 Chain 來執行 Handler 已達成目的

備註:


  • 如您目前是團隊工作,則請遵守團隊所訂下的撰寫規範,此篇文章僅為參考建議使用
  • 在.Net Core 上的模組化已經可以單純用 AddChain or AddCrawler 來完成
  • 這也是為什麼在.Net Core上可以 AddMvc 的理由,當然啦,實際內容不會像上面那樣單純
  • 透過同樣的設定方式做為開發的準則,我個人是覺得可以有效幫助程式的質感和泛用性