在接口的多种实现中违反SOLID原则 [英] Breaking SOLID Principles in multiple implementation of an Interface

查看:200
本文介绍了在接口的多种实现中违反SOLID原则的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在factory方法中面临依赖倒置的问题,它也打破了开放式封闭原则.我的代码看起来像下面的代码

I am facing a problem with dependency inversion in a factory method and it is also breaking Open Closed principle. My code looks like below codes

    public interface IWriter
    {
        void WriteToStorage(string data);
    }

    public class FileWriter : IWriter
    {
        public void WriteToStorage(string data)
        {
            //write to file
        }
    }

    public class DBWriter : IWriter
    {
        public void WriteToStorage(string data)
        {
            //write to DB
        }
    }

现在,我使用工厂类来解决对象的创建.看起来像下面的代码

Now I an using a factory class to solve the object creation. It look like below code

public interface IFactory
{
    IWriter GetType(string outputType);
}

public class Factory : IFactory
{
    public IWriter GetType(string outputType)
    {
        IWriter writer = null;
        if (outputType.Equels("db"))
        {
            writer = new FileWriter();
        }
        else if (outputType.Equels("db"))
        {
            writer = new DBWriter();
        }
    }
}

现在的问题是Factory类违反了开放式封闭原则,因此它也违反了依赖倒置原则

Now the problem is the Factory class is breaking Open closed principle so it also breakes Dependency Inversion Principle

然后

public interface ISaveDataFlow
{
    void SaveData(string data, string outputType);
}

public class SaveDataFlow : ISaveDataFlow
{
    private IFactory _writerFactory = null;
    public SaveDataFlow(IFactory writerFactory)
    {
        _writerFactory = writerFactory;
    }
    public void SaveData(string data, string outputType)
    {
        IWriter writer = _writerFactory.GetType(outputType);
        writer.WriteToStorage(data);
    }
}

由于上面的工厂类打破了依赖倒置,我删除了Factory类,并更改了SaveDataFlow类,如下所示:

As the above factory class is breaking the dependency inversion I remove the Factory class and change the SaveDataFlow class like below

public class SaveDataFlow : ISaveDataFlow
{
    private IWriter _dbWriter = null;
    private IWriter _fileWriter = null;
    public SaveDataFlow([Dependency("DB")]IWriter dbWriter,
                        [Dependency("FILE")]IWriter fileWriter)
    {
        _dbWriter = dbWriter;
        _fileWriter = fileWriter;
    }
    public void SaveData(string data, string outputType)
    {
        if (outputType.Equals("DB"))
        {
            _dbWriter.WriteToStorage(data);
        }
        else if (outputType.Equals("FILE"))
        {
            _fileWriter.WriteToStorage(data);
        }
    }
}

并使用Unity Framework解决了这些依赖关系

And resolved those dependencies using Unity Framework

container.RegisterType<IWriter, DBWriter>("DB");
container.RegisterType<IWriter, FileWriter>("FILE");

但是,最终我最终打破了开放式封闭原则. 我需要更好的设计/解决方案来解决此类问题,但我必须遵循SOLID原则.

Yet eventually I am ending up breaking Open Closed Principle. I need a better design/solution to solve such a problem yet I must follow SOLID Principles.

推荐答案

我只是将其转变为策略模式:

I would simply turn it into a strategy pattern:

namespace UnityMutliTest
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using Microsoft.Practices.Unity;

    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer();

            container.RegisterType<IWriter, FileWriter>("file");
            container.RegisterType<IWriter, DbWriter>("db");

            container.RegisterType<IWriterSelector, WriterSelector>();

            var writerSelector = container.Resolve<IWriterSelector>();

            var writer = writerSelector.SelectWriter("FILE");

            writer.Write("Write me data");

            Console.WriteLine("Success");

            Console.ReadKey();
        }
    }

    interface IWriterSelector
    {
        IWriter SelectWriter(string output);
    }

    class WriterSelector : IWriterSelector
    {
        private readonly IEnumerable<IWriter> writers;

        public WriterSelector(IWriter[] writers)
        {
            this.writers = writers;
        }

        public IWriter SelectWriter(string output)
        {
            var writer = this.writers.FirstOrDefault(x => x.CanWrite(output));

            if (writer == null)
            {
                throw new NotImplementedException($"Couldn't find a writer for {output}");
            }

            return writer;
        }
    }

    interface IWriter
    {
        bool CanWrite(string output);

        void Write(string data);
    }

    class FileWriter : IWriter
    {
        public bool CanWrite(string output)
        {
            return output == "FILE";
        }

        public void Write(string data)
        {
        }
    }

    class DbWriter : IWriter
    {
        public bool CanWrite(string output)
        {
            return output == "DB";
        }

        public void Write(string data)
        {
        }
    }
}

您可以根据需要拥有任意数量的IWriter,只需注册它们即可:

You can have as many IWriters as you want, just register them:

container.RegisterType<IWriter, LogWriter>("log");

如果您愿意,甚至可以在编写器上实现装饰器.

You can even implement decorators over the writers if you want as well.

您使用(错误命名的)IWriterSelector作为如何选择作家的实现,这应该只涉及获得作家! throw异常在这里非常有用,如果没有适合您需要的实现,它将很快失败!

You use the (badly named) IWriterSelector as the implementation on how to select your writer, this should be concerned with only getting a writer! The throw exception here is really useful, it will fail fast if there is no implementation that suits your needs!!

如果您遇到Open Closed问题,请使用策略"或模板"模式来克服.

If you ever have Open Closed problems, either use Strategy or Template patterns to overcome.

我一直使用这种模式,效果很好.

I use this pattern all the time, to great effect.

我创建了一个扩展方法,以防止您不得不命名实例:

I've created a little extension method to prevent you having to name your instances:

static class UnityExtensions
{
    public static void RegisterMultipleType<TInterface, TConcrete>(this IUnityContainer container)
    {
        var typeToBind = typeof(TConcrete);
        container.RegisterType(typeof(TInterface), typeToBind, typeToBind.Name);
    }
}

container.RegisterMultipleType<IWriter, FileWriter>();

这篇关于在接口的多种实现中违反SOLID原则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆