conception de classe: permettent qu'une classe soit utilisée à la fois comme un objet et également fournir des méthodes statiques publiques

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

Question

J'ai un idiot, petite classe « FileSystemSize » qui peut être utilisé à la fois comme un objet et également par l'intermédiaire du public, des méthodes statiques. La sortie est similaire, mais pas identique dans chaque cas.

La classe était intially statique , mais j'ajouté la possibilité d'initialiser comme un objet pour permettre extension avec de nouvelles « méthodes convenience » dans les versions futures, sans qu'il soit nécessaire pour beaucoup d'analyse des paramètres. Par exemple, j'ai GetKBString () , GetMBString () , etc ... des méthodes pour permettre d'obtenir la taille du fichier facilement formaté la façon dont je veux (comme une chaîne). En interne, la classe stocke la taille des octets de fichier en tant que double.

Je suis un peu confus si cela fait sens. Il semble que je devrais peut-être découpé dans une version statique et une version d'objet comme Microsoft fait pour Directory et DirectoryInfo. Cependant, il semble juste plus facile pour moi d'avoir tout cela en un seul endroit avec un nom qui ne peut pas être confondu avec - il devrait être clair que FileSystemSize fait? Y a-t-il des conséquences pour l'entretien que je ne suis pas Anticiper? Quelle est cette odeur?

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");
Était-ce utile?

La solution

Regardez une autre façon: Pourquoi mettez-vous chaîne / nombre / méthodes de mise en forme de l'interface utilisateur dans votre méthode FileSystemSize

Bien qu'il puisse être utilisé pour des fichiers, c'est un morceau général de fonctionnalité qui à mon humble avis doit être trouvée ailleurs dans une bibliothèque bien organisée - comme fonctions de chemin ne font pas partie des classes de fichier ou un répertoire .net, je placerait les méthodes « formater un nombre » dans une chaîne ou mathématiques classe utils.

Séparez les responsabilités de vos objets et vous trouverez peut-être qu'il n'y a pas besoin de mélanger les membres statiques et non statiques dans des cas comme celui-ci.

Autres conseils

Un bon test. Si vous vous et nous demander si elle est d'accord, il y a une chance qu'il est pas

Il ne peut pas être naturel pour les utilisateurs de la classe d'avoir des méthodes accessibles par classe et d'autres via l'objet, en particulier lorsque le second ne nécessitent pas vraiment les propriétés d'instance de la classe. Les chances sont qu'ils seront confus et référerons à aimer. « ?! WTF ce programmeur a fait que »

Je suggère d'aller avec toutes les méthodes d'exemple, si vous aimez la possibilité d'étendre la classe, que ce soit avec des méthodes d'extension ou par sous-classement.

Puisque vous n'êtes pas avoir beaucoup d'état dans FileSystemSize, est-ce pas le candidat idéal pour les méthodes d'extension?

Je personnellement fournir des extensions aux numéros de format sous forme de chaînes de taille de fichier et d'utiliser un enum pour indiquer comment formater la taille des fichiers:

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,
}

Si vous utilisez C # 3.0, vos intentions peuvent être mieux exprimées par les méthodes d'extension et IFormatProviders. Dans le code, cela pourrait être une méthode d'extension sur les méthodes toString FileInfo et DirectoryInfo, donc ils lirait quelque chose comme ceci:

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

Le code ci-dessus se sent plus naturel pour ce que vous essayez de faire.

Voyez comment les œuvres suivantes pour vous. Certaines d'entre elles devront être testées (la DirectoryInfoExtender.GetDirectorySize méthode récursive vient à l'esprit). Si vous devez être en mesure d'écrire des déclarations comme Console.WriteLine("{0:GB}", fileInfo), vous pouvez également envisager d'écrire un IFormatProvider ainsi.

Notez également que j'ai volontairement lésiné sur les chèques nuls et la gestion des exceptions pour ces méthodes accessibles au public.

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);
    }
}

odeur standard est l'utilisation de méthodes statiques -. Il est donc difficile de maintenir dans le cas où vous utilisez ces méthodes tout votre code

Une autre IMHO odeur est: nom de classe n'est pas clair sur ce qu'il fait. D'après votre description, il est destiné aux données de format dans ce cas, je voudrais mentionner dans le nom de la classe.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top