views:

77

answers:

2

I'm developing a class to compare two directories and run an action when a directory/file in the source directory does not exist in destination directory.

Here is a prototype of the class:

public abstract class IdenticalDirectories
{

    private DirectoryInfo _sourceDirectory;
    private DirectoryInfo _destinationDirectory;

    protected abstract void DirectoryExists(DirectoryInfo sourceDirectory, DirectoryInfo destinationDirectory);
    protected abstract void DirectoryDoesNotExist(DirectoryInfo sourceDirectory, DirectoryInfo destinationDirectory);
    protected abstract void FileExists(DirectoryInfo sourceDirectory, DirectoryInfo destinationDirectory);
    protected abstract void FileDoesNotExist(DirectoryInfo sourceDirectory, DirectoryInfo destinationDirectory);

    public IdenticalDirectories(DirectoryInfo sourceDirectory, DirectoryInfo destinationDirectory)
    {
        ...
    }

    public void Run()
    {

        foreach (DirectoryInfo sourceSubDirectory in _sourceDirectory.GetDirectories()) 
        {
            DirectoryInfo destinationSubDirectory = this.GetDestinationDirectoryInfo(subDirectory);

            if (destinationSubDirectory.Exists()) {
                this.DirectoryExists(sourceSubDirectory, destinationSubDirectory);
            } else {
                this.DirectoryDoesNotExist(sourceSubDirectory, destinationSubDirectory);
            }

            foreach (FileInfo sourceFile in sourceSubDirectory.GetFiles()) {
                FileInfo destinationFile = this.GetDestinationFileInfo(sourceFile);

                if (destinationFile.Exists()) {
                    this.FileExists(sourceFile, destinationFile);
                } else {
                    this.FileDoesNotExist(sourceFile, destinationFile);
                }
            }
        }
    }
}

The above prototype is an abstract class. I'm wondering if it would be better to make the class non-abstract and have the Run method receiver a processor? eg.

public void Run(IIdenticalDirectoriesProcessor processor)
{

    foreach (DirectoryInfo sourceSubDirectory in _sourceDirectory.GetDirectories()) {
        DirectoryInfo destinationSubDirectory = this.GetDestinationDirectoryInfo(subDirectory);

        if (destinationSubDirectory.Exists()) {
            processor.DirectoryExists(sourceSubDirectory, destinationSubDirectory);
        } else {
            processor.DirectoryDoesNotExist(sourceSubDirectory, destinationSubDirectory);
        }


        foreach (FileInfo sourceFile in sourceSubDirectory.GetFiles()) {
            FileInfo destinationFile = this.GetDestinationFileInfo(sourceFile);

            if (destinationFile.Exists()) {
                processor.FileExists(sourceFile, destinationFile);
            } else {
                processor.FileDoesNotExist(sourceFile, destinationFile);
            }

        }

    }

}

What do you see as the pros and cons of each implementation?

+2  A: 

Passing in an IIdenticalDirectoriesProcessor can give you dynamic runtime flexibility and can make the IdenticalDirectories class easier to test and won't couple the implementation of the IIdenticalDirectoriesProcessor to the IdenticalDirectories class like the abstract/derived class solution you originally proposed.

When I only have 1 or 2 abstract methods to override these days I often just accept Func or Action delegates instead of creating an interface. This gives you the highest degree of de-coupling. Any more than 1 or 2 however and it becomes clunky so you'd want to choose a more traditional implementation.

Just my opinions, mind.

Phil Bennett
+2  A: 

In .NET, a delegate is the preferred way of implementing a callback. In other languages where delegates are not supported (i.e. most versions of Java) then interfaces are common, sometimes with a class providing a default implementation of the interface.

In languages which support only single inheritance, there's a definite downside to using an abstract class: it uses up the consumer's one inheritance slot. This isn't a problem with interfaces.

Ben Voigt