![](/img/trans.png)
[英]Class design: public constructor or private with static factory and a COM object
[英]Class design: allow a class to be used both as an object and also supply public static methods
我有一个愚蠢的小类“ FileSystemSize ”,它既可以用作对象,也可以通过公共静态方法使用。 输出是相似的,但在每种情况下都不相同。
该类最初是静态的 ,但我添加了将其初始化为对象的可能性,以允许在将来的版本中使用新的“ 便捷方法 ”进行扩展,而无需进行大量参数解析。 例如,我有GetKBString() , GetMBString()等方法,可让您方便地以我想要的方式格式化文件大小(作为字符串)。 在内部,该类将文件字节大小存储为双精度。
如果这完全有意义,我会感到困惑。 似乎我应该将其拆分为静态版本和对象版本,例如Microsoft用于Directory和DirectoryInfo的版本。 但是,对我来说,将所有这些都放在一个地方且名称不能误会似乎更容易-应该清楚FileSystemSize的作用是什么? 对维护我没有任何影响吗? 那是什么味道?
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");
换一种方式来看:为什么要在FileSystemSize方法中放入String / Number / UI格式化方法?
尽管可以将其用于文件,但这是IMHO的常规功能,应该在组织良好的库中的其他位置找到–正如Path函数不是.net中File或Directory类的一部分一样,我将字符串或maths utils类中的“格式化数字”方法。
将对象的职责分开,您可能会发现在这种情况下无需混合静态成员和非静态成员。
一个很好的测试:如果您要问自己和我们是否还可以,则有可能不这样做。
对于类的用户来说,使某些方法可以通过类访问而另一些方法可以通过对象访问是不自然的,尤其是当第二种方法实际上不需要类的实例属性时。 他们很可能会感到困惑,并且会像这样说:“这个程序员做的是WTF吗?!”。
如果您希望通过扩展方法或通过子类扩展类,则建议使用所有实例方法。
由于FileSystemSize中没有很多状态,因此这不是扩展方法的理想之选吗?
我将亲自提供扩展名,以将数字格式化为文件大小字符串,并使用一个enum
来指定如何格式化文件大小:
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,
}
如果您使用的是C#3.0,则可以通过扩展方法和IFormatProviders更好地表达您的意图。 在代码中,这可能是FileInfo和DirectoryInfo ToString方法的扩展方法,因此它们将读取以下内容:
var directorySize = myDirectory.ToString("GB");
var fileSize = myFile.ToString("MB");
上面的代码对于您尝试执行的操作而言更为自然。
请参阅以下内容。 其中一些将需要测试(想到递归方法DirectoryInfoExtender.GetDirectorySize)。 如果您需要能够编写类似Console.WriteLine("{0:GB}", fileInfo)
类的语句,则还可以考虑编写IFormatProvider。
还要注意,我故意跳过了这些公共可访问方法的空检查和异常处理。
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);
}
}
标准气味是静态方法的使用-如果在整个代码中都使用这些方法,则很难维护。
另一个气味恕我直言是:类名不清楚其实际作用。 从您的描述开始,它的意思是格式化数据,在这种情况下,我会在类名中提到它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.