简体   繁体   中英

How to refactor abstract method to DI

I have Asp.net Core project with default DI realization. So I get BL-services instances, repositories, EF-context by DI. I have abstract method that returns certain type by parameter.

IDocumentPreprocessor CreateDocumentPreprocessor(DocType docType)
    {
        switch (docType)
        {
            case DocType.Txt:
                return new TxtPreprocessor(_context, _docRepository);
            case DocType.Doc:
                return new DocPreprocessor(_docRepository);

            default:
                throw new ...
        }
    }

I don't like here direct creation of instance by "new". But I'm not sure if it's possible to pass this logic to DI. So the question - how to refactor it to DI usage?

You wrap the logic in yet another DI-injectable service: an IDocumentPreprocessorFactory . There you inject factory methods for IDocumentPreprocessor implementations.

public interface IDocumentPreprocessorFactory
{
    IDocumentPreprocessor CreateDocumentPreprocessor(DocType docType);
}

public class DocumentPreprocessorFactory : IDocumentPreprocessorFactory
{
    private readonly Func<TxtPreprocessor> createTxtPreprocessor;

    private readonly Func<DocPreprocessor> createDocPreprocessor;

    public DocumentPreprocessorFactory(
        Func<TxtPreprocessor> createTxtPreprocessor,
        Func<DocPreprocessor> createDocPreprocessor)
    {
        this.createTxtPreprocessor = createTxtPreprocessor;
        this.createDocPreprocessor = createDocPreprocessor;
    }

    public IDocumentPreprocessor CreateDocumentPreprocessor(DocType docType)
    {
        switch (docType)
        {
            case DocType.Txt:
                return this.createTxtPreprocessor();
            case DocType.Doc:
                return this.createDocPreprocessor();
            default:
                throw new...
        }
    }
}

You must now extend your DI setup with the registrations of the factory methods. I have not used Core's DI yet, but I believe it might look something like this

services.AddSingleton<Func<DocPreprocessor>>(ctx => () => ctx.GetService<DocPreprocessor());
services.AddSingleton<Func<TxtPreprocessor>>(ctx => () => ctx.GetService<TxtPreprocessor());

this is can be help you..

        // object lifetime transient or others.. determine according to your needs
        services.AddTransient<TxtPreprocessor>();
        services.AddTransient<DocPreprocessor>();
        services.AddTransient(processorFactory =>
        {
            Func<DocType, IDocumentPreprocessor> factoryFunc = docType =>
            {
                switch (docType)
                {
                    case DocType.Txt:
                        return processorFactory.GetService<TxtPreprocessor>();
                    default:
                        return processorFactory.GetService<DocPreprocessor>();// DocPreprocessor is defult
                }
            };
            return factoryFunc;
        });

usage in any registered class..

public class AnyClass
{
    private readonly IDocumentPreprocessor _documentProcessor;

    public AnyClass(Func<DocType, IDocumentPreprocessor> factoryFunc)
    {
        _documentProcessor =  factoryFunc(DocType.Doc);
    }
}

you can encapsulate this function with factory class, if you want

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM