hiding internal services from outside world to ensure the correct high-level service is being used [closed]

前提是你 提交于 2019-12-13 07:59:54

问题


I am working on an e-commerce website. I have advertisement entity which include both properties and photos. Properties are written to DB and photos are stored in file system.

I have created a WriterService in my infrastructure project, this service is responsible to save an ad... under the hood it should know that properties go to DB and photos go to file system... but this details is irrelevant to the outside world... the outside world should use WriterService to save an ad.

This is my writer service:

public class WriterService
{
    private DbWriter _dbWriter;
    private IFileWriter _fileWriter;

    // I believe I need to change the constructor in order to achieve my goal
    public WriterService(DbWriter dbWriter, IFileWriter fileWriter)
    {
        _dbWriter = dbWriter;
        _fileWriter = fileWriter;
    }

    public void WriterSomething(string text, Stream image)
    {
        _dbWriter.Write(text);
        _fileWriter.Write(image);
    }
}

Now in my infrastructure layer I have the implementation of DbWriter and FileWriter, DbWriter looks like this:

public DbWriter
{
    public void Write(string text) {/* write text to DB */}
}

FileWriter can have different implementations:

public interface IFileWriter
{
   void Write(Stream image);
}

Photos may be writter to local disk or AWS S3 bucket:

public DiskDriveWriter : IFileWriter
{
    public void Write(Stream image) {/* write image to Disk */}
}

public AWSCloudWriter : IFileWriter
{
    public void Write(Stream image) {/* write image to AWS */}
}

I want to enforce the outside world (other projects in my solution) to use WriterService, so if they want to save some images they should not directly use AWSCloudWriter, they would always have to do this through WriterService. Is it possible to enforce this?


Update

I order to avoid a very long question, I have created this code review explaining the problem that I am trying to solve.


回答1:


I used an adapter to map the intermediate class to the final AWS/Disk writers thus hiding them from the implementer.

All of this code is in a separate class library

IFileWriter

    internal interface IFileWriter
    {
        void Write(string text);
    }

Two classes implementing the IFileWriter

    internal class AWSWriter : IFileWriter
    {
        public void Write(string text)
        {
            //Write to AWS
        }
    }
    internal class DiskDriveWriter : IFileWriter
    {
        public void Write(string text)
        {
            //Write to disk
        }
    }

Abstract Base class for the adapter

    public abstract class AbstractFileWriterAdapter
    {
        internal IFileWriter FileWriter { get; set; }
    }

Two adapters, one for AWS and another for the DiskWriter

    public class AWSFileWriterAdapter: AbstractFileWriterAdapter
    {
        public AWSFileWriterAdapter()
        {
            FileWriter = new AWSWriter();
        }
    }
    public class DiskDriveWriterAdapter:AbstractFileWriterAdapter
    {
        public DiskDriveWriterAdapter()
        {
            FileWriter = new DiskDriveWriter();
        }
    }

WriterService

public class WriterService
{
    AbstractFileWriterAdapter _writer;

    public WriterService(AbstractFileWriterAdapter writer)
    {
        _writer = writer;
    }

    public void WriteMessage(string text)
    {
        _writer.FileWriter.Write(text);
    }
}

Finally the calls from a different project

            var awsAdapter = new AWSFileWriterAdapter();
            var service1 = new WriterService(awsAdapter);
            service1.WriteMessage("Some fancy text to AWS!!");


            var diskDriveAdapter = new DiskDriveWriterAdapter();
            var service2 = new WriterService(diskDriveAdapter);
            service2.WriteMessage("Some text to the drive!!");



回答2:


It will work if you make IFileWriter internal and the constructor for WriterService that takes your interface should also be made internal.

internal interface IFileWriter
internal WriterService(IFileWriter fileWriter)

Something like this:

internal interface IWriter
{
    void Write(string text);
}

internal class WriterB : IWriter
{
    public void Write(string text) { Console.WriteLine($"A is writing '{text}'"); }
}

internal class WriterA : IWriter
{
    public void Write(string text) { Console.WriteLine($"B is writing '{text}'"); }
}

public class WriterService
{
    private readonly IWriter x;

    internal WriterService(IWriter x) { this.x = x; }

    public void Write(string text) { x.Write(text); }

    public static WriterService WithA() { return new WriterService(new WriterA()); }

    public static WriterService WithB() { return new WriterService(new WriterB()); }
}


public class Program
{
    public static void Main(string[] args)
    {
        var s = new WriterService(new WriterA());

        s.Write("Hello!");

        WriterService.WithA().Write("Hello again!");

        WriterService.WithB().Write("And again!");
    }
}


来源:https://stackoverflow.com/questions/58279281/hiding-internal-services-from-outside-world-to-ensure-the-correct-high-level-ser

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!