问题
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