我在始终使用组合的概念上苦苦挣扎,有很多文章提到几乎所有继承的使用都可以用组合代替。我知道它有诸如测试之类的好处...但是在这种情况下,如何替换继承的使用?
基本上,我有2个装饰器,它们向现有的文件服务类添加功能。在复制文件之前,我希望它重命名它们,然后委派回原始文件服务。
在此示例中,我有两种方法。一个循环通过理论上的文件列表,然后调用“复制文件”。装饰器类无需复制代码,而只需调用包装的实现版本,类似于利用继承。
但是,这不能像继承那样工作,因为现在它永远不会调用装饰器CopyFile方法,因为它现在在先前的基类实现中,它不知道装饰器CopyFile方法存在。
如果我使用继承,则通过将方法标记为虚方法,基类将知道何时重写其功能之一,并调用该版本而不是其版本。
如何仅使用合成来模仿此功能?
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp5
{
public interface IFileService
{
void CopyFile(string source, string destination);
void CopyFiles(IEnumerable<string> source, string destination);
}
public class MainFileService : IFileService
{
public void CopyFile(string source, string destination)
{
Console.WriteLine("Base Method of Copy File invoked");
}
public void CopyFiles(IEnumerable<string> source, string destination)
{
foreach (var file in source)
{
CopyFile(file,destination);
}
}
}
public class RenamingFileService : IFileService
{
private IFileService _wrapper;
public RenamingFileService(IFileService wrapper)
{
this._wrapper = wrapper;
}
public void CopyFile(string source, string destination)
{
RenameFileExtensionToPART();
_wrapper.CopyFile(source, destination);
}
private void RenameFileExtensionToPART()
{
Console.WriteLine($"Now invoking {nameof(RenameFileExtensionToPART)}");
}
public void CopyFiles(IEnumerable<string> source, string destination)
{
_wrapper.CopyFiles(source, destination);
}
}
public class FileLoggingService : IFileService
{
private IFileService _wrapper;
public FileLoggingService(IFileService wrapper)
{
this._wrapper = wrapper;
}
public void CopyFile(string source, string destination)
{
Console.WriteLine("Logged Request");
_wrapper.CopyFile(source, destination);
}
public void CopyFiles(IEnumerable<string> source, string destination)
{
Console.WriteLine("Logging requests.");
_wrapper.CopyFiles(source, destination);
}
}
class Program
{
static void Main(string[] args)
{
var service = new FileLoggingService(new RenamingFileService(new MainFileService()));
service.CopyFiles(Enumerable.Range(0,10).Select(x => Guid.NewGuid().ToString()),"Directory");
}
}
}