Design de classe: permita que uma classe seja usada como objeto e também forneça métodos estáticos públicos

StackOverflow https://stackoverflow.com/questions/1384100

Pergunta

Eu tenho uma classe boba e pequena "FileSystemSize"Que pode ser usado como objeto e também por métodos estáticos públicos. A saída é semelhante, mas não idêntica em cada caso.

A aula era intimamente estático, mas adicionei a possibilidade de inicializá -lo como um objeto para permitir a extensão com o novo "Métodos de conveniência"Em versões futuras, sem a necessidade de muita análise de parâmetros. Por exemplo, eu tenho Getkbstring (), GetMbstring (), etc ... Métodos para permitir que o tamanho do arquivo formatasse convenientemente da maneira que eu quero (como uma string). Internamente, a classe armazena o tamanho do byte de arquivo como um dobro.

Estou um pouco confuso se isso faz sentido. Parece que eu talvez deva dividir isso em uma versão estática e uma versão de objeto como a Microsoft faz para o Directory e o DirectoryInfo. No entanto, parece mais fácil para mim ter tudo isso em um só lugar com um nome que não pode ser enganado - deve ficar claro o que o Sistema de arquivos faz? Existem implicações para a manutenção que eu não estou antecipando? Que cheiro é esse?

var mypath = @"C:\mypath";

var filesystemsize = new FileSystemSize(mypath);
string kilobytes = filesystemsize.GetKBString();
string megabytes = filesystemsize.GetMBString();
double bytes = filesystemsize.ByteSize;

double staticbytes = FileSystemSize.GetDirectoryBytesSize(new DirectoryInfo(mypath));
double statickilobytes = FileSystemSize.ConvertSize(staticbytes, "KB");
Foi útil?

Solução

Veja de outra maneira: por que você está colocando métodos de formatação de string/número/UI no seu método de Sistema de arquivos?

Embora possa ser usado em relação aos arquivos, essa é uma peça geral de funcionalidade que o IMHO deve ser encontrado em outras partes de uma biblioteca bem organizada - assim como as funções do caminho não fazem parte do arquivo ou das classes de diretório em .NET, eu colocaria o Métodos "formato de um número" em uma classe String ou Maths Utils.

Separe as responsabilidades de seus objetos e você pode descobrir que não há necessidade de misturar membros estáticos e não estáticos em casos como este.

Outras dicas

Um bom teste: se você está se perguntando a si e a nós se está tudo bem, há uma chance de que não seja.

Pode não ser natural que os usuários da classe tenham alguns métodos acessíveis via classe e outros via objeto, especialmente quando o segundo não exige realmente as propriedades da instância da classe. Provavelmente, eles ficarão confusos e estarão se referindo a: "WTF Este programador fez isso?!".

Sugiro seguir todos os métodos de instância, se você gosta da possibilidade de estender a classe, com métodos de extensão ou via subclasse.

Como você não está tendo muito estado no FileSystemSize, esse não é o candidato perfeito para métodos de extensão?

Eu pessoalmente forneceria extensões para formatar números como seqüências de tamanho de arquivo e usar um enum Para especificar como formatar os tamanhos dos arquivos:

public static class FileSystemSize
{
    public static long GetDirectoryBytesSize(string path);
}

public static class NumberExtensions
{
    public static string FormatAsFileSize(
        this long fileSize, FileSizeStringFormat format);
}

public enum FileSizeStringFormat
{
    KiloByte,
    MegaByte,
}

Se você estiver usando o C# 3.0, suas intenções poderão ser melhor expressas com métodos de extensão e IFORMATPROVERS. No código, esse pode ser um método de extensão nos métodos FileInfo e DirectoryInfo ToString, para que eles lessem algo assim:

var directorySize = myDirectory.ToString("GB");
var fileSize = myFile.ToString("MB");

O código acima parece mais natural para o que você está tentando fazer.

Veja como o seguinte funciona para você. Algumas delas precisarão ser testadas (o método recursivo DirectoryInfoextender.GetDirectorySize vem à mente). Se você precisar escrever declarações como Console.WriteLine("{0:GB}", fileInfo), você também pode considerar escrever um IformatProvider também.

Observe também que eu intencionalmente economizei em verificações nulas e manuseio de exceções para esses métodos publicamente acessíveis.

public static class DirectoryInfoExtender
{
    public static string ToString(this DirectoryInfo d, string format, int fractionalDigits)
    {
        double fileSize = GetDirectorySize(d);
        return FileSizeConverter.GetFileSizeString(fileSize, format, fractionalDigits);
    }

    public static double GetDirectorySize(DirectoryInfo d)
    {    
        var files = d.GetFiles();
        var directories = d.GetDirectories();

        if(files.Length == 0 && directories.Length == 0)
        {
            return 0;
        }
        else
        {
            double size = 0;

            foreach(var file in files)
            {
                size += file.Length;
            }

            foreach(var directory in directories)
            {
                size += GetDirectorySize(directory);
            }
        }

        return size;
    }
}


public static class FileInfoExtender
{
    public static string ToString(this FileInfo f, string format, int fractionalDigits)
    {
        return FileSizeConverter.GetFileSizeString(f.Length, format, fractionalDigits);
    }
}

public class FileSizeConverter
{
    public static string GetFileSizeString(double fileSize, string format, int fractionalDigits)
    {
        long divisor;
        string sizeIndicator;

        switch(format.ToLower().Trim())
        {
            case "gb":
                divisor = (long)Math.Pow(2, 30);
                sizeIndicator = "gigabytes";
                break;
            case "mb":
                divisor = (long) Math.Pow(2, 20);
                sizeIndicator = "megabytes";
                break;
            case "kb":
                divisor = (long)Math.Pow(2, 10);
                sizeIndicator = "kilobytes";
                break;
            default:
                divisor = 1;
                sizeIndicator = "bytes";
                break;
        }

        return String.Format("{0:N" + fractionalDigits +"} {1}", fileSize / divisor, sizeIndicator);
    }
}

O cheiro padrão é o uso de métodos estáticos - isso dificulta a manutenção, caso você use esses métodos em todo o seu código.

Outro cheiro IMHO é: o nome da classe não está claro sobre o que realmente faz. A partir da sua descrição, é destinado a formatar dados, caso em que eu o mencionaria no nome da classe.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top