Как мне имитировать виртуальные методы только с использованием композиции? - PullRequest
0 голосов
/ 08 ноября 2018

Я борюсь с понятием всегда использовать композицию, есть много статей, в которых упоминается, что практически все виды использования наследования могут быть заменены композицией.Я понимаю, что есть такие преимущества, как тестирование ... но как я могу заменить использование наследования в этом случае?

В основном у меня есть 2 декоратора, которые добавляют функциональность к существующему классу файловой службы.Прежде чем копировать файлы, я хочу переименовать их, а затем делегировать обратно в исходную файловую службу.

В этом примере у меня есть два метода.Один перебирает теоретический список файлов, а затем вызывает Copy File.Вместо дублирования кода класс декоратора просто вызывает вместо этого версию обернутых реализаций, подобно использованию наследования.

Однако это не работает как наследование, потому что теперь он никогда не будет вызывать метод 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");
    }
}

}

...