![](/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.