[英]How should I write my Factory Class - Generates derived objects
首先,我將列出我的一般設置並描述課程的目標,因為我覺得它對這個問題很重要:
public enum SyncMode
{
None = -2, // SyncMode Not Defined by Object (don't actually intend in my use case, added for future compatibility/interfaces)
AlwaysReturnNetwork = -1, //DynamicPath should prioritize the network string, UNLESS the network is unavailable and the path exists locally.
Dynamic = 0, // Another one for potential future objects
OfflineCache = 1, // Allow file/folder to be downloaded for use in offline mode of the application
LocalCache = 2, // Cache the file/folder locally for quicker access
AlwaysReturnLocal = 3, // Designed to essentially be a file that is required by the application
}
// this class will allow consumers to override some functions, for example the actions to take when downloading the file from remote to local.
//(base will assume its not web-based, so a web-based consumer will need to implement that functionality by overriding the virtual methods)
// As shown below, the consumer must also specify how to determine if the user is set up to local/offline cache, as well as if the application is running in offline (assume network unavailable) mode
public abstract class FileOperations
{
abstract bool IsApplicationOffline {get;}
abstract bool AllowOfflineCaching {get;}
abstract bool AllowLocalCaching {get;}
}
public abstract class AbstractNetworkPath
{
public string LocalPath { get; } // File/Folder might exist at this location on the pc
public string NetPath { get; } // File/Folder should exist at this location on a remote location
public SyncMode SyncMode {get;} //Determine how the DynamicPath functions
public string DynamicPath {get;} //String is returned based on the SyncMode value and if the path exists locally
protected bool ShouldCache => SyncMode == AlwaysReturnLocal || SyncMode >=OfflineCache && FileOps.AllowOfflineCaching || SyncMode >= LocalCaching && FileOps.AllowLocalCaching;
internal protected FileOperations FileOps {get;} // Reference to the object passed into the ctor/factory
}
public class SyncedFile : AbstractNetworkPath
{
public void CopyTo(string destPath)
{
if (ShouldCache) this.FileOps.UpdateFile(this.NetPath, this.LocalPath);
FileOps.CopyFile(this.DynamicPath, destPath);
}
}
public class NetworkFolder: AbstractNetworkPath
{
// This class represents a remote folder, and prioritizes the network location
// This is meant to specify some location, not necessarily one that gets downloaded.
// For example, a main directory with a bunch of files/folders, most of which the application doesn't need or want.
}
public class SyncedFolder : NetworkFolder
{
// This class represents a remote folder, but prioritizes the local location
// This class also adds the methods to download the folder locally
public void CopyTo(string destPath)
{
if (ShouldCache) this.FileOps.UpdateFolder(this.NetPath, this.LocalPath);
FileOps.CopyFolder(this.DynamicPath, destPath);
}
}
所以這就是有趣的地方:
以下是問題:
我的計划是擁有一個SyncedFileFactory
、一個NetworkFolderFactory
和一個SyncedFolderFactory
擁有一個將其 SyncMode 應用於正在構造的類的工廠是否有意義? 還是一個更通用的工廠,它只是驗證傳遞給方法的 SyncMode?
這是我目前所擁有的:
public class SyncedFileFactory
{
Public SyncedFileFactory(SyncMode syncmode, FileOperations fileOps) { /* Ctor*/ }
public FileOperations FileOperationsObj{get;}
Public SyncMode SyncMode {get;}
}
public class NSOFactory
{
Public NSOFactory(FileOperations fileOps)
{
FileFactory_Offline = new(SyncMode.OfflineCache, fileOps);
FileFactory_LocalCache = new(SyncMode.LocalCache, fileOps);
FileFactory_Required = new(SyncMode.AlwaysReturnLocal, fileOps);
}
public SyncedFileFactory FileFactory_Offline {get;}
public SyncedFileFactory FileFactory_LocalCache {get;}
public SyncedFileFactory FileFactory_Required {get;}
}
我喜歡這強制 SyncModes 的類型,並且只構造具有有效同步模式的對象,但是當從已經指定了 syncMode 的對象構造時,我們遇到了一些問題,我不確定解決這個問題的最佳方法同時保持工廠結構清晰
編輯:可能的解決方案 - 需要考慮這個:
所以現在我的思路基本上是:
OfflineCache
應該優先於LocalCache
,用於構造,但AlwaysReturnLocal
是構造的最高優先級。 那么我是否只是評估輸入父級和選擇的工廠並采取相應的行動? 這可能是最容易做到的事情。 但是如果有人去看它,你最終會得到與輸入值不同的輸出值。 這種交互降低了清晰度,但與庫的預期功能保持一致。好的,所以當我繼續開發這個 dll 時,我遇到了一些其他問題,這些問題已經解決了。 對於可能受到啟發的其他人,我將在下面詳細說明我的解決方案。
原始思維過程:創建每個 SyncMode 類型的工廠(至少是主要值)。 我想到想要它的原因:
這方面的問題:
原始計划:有一個庫引用的全局設置對象負責定義Func<bool>
目標,以確定應用程序是否處於離線模式,是否允許本地緩存等。問題:
解決方案:
NSOFactorySettings
類型的屬性。所有派生類現在都指向此屬性,而不是靜態類。)用於強制執行特定枚舉的結構:
/// <summary>
/// Subset of <see cref="SyncMode"/> values that are valid for <see cref="SyncedFile"/> and <see cref="SyncedFolder"/> objects.
/// </summary>
[ImmutableObject(true)]
public readonly struct CacheMode
{
private CacheMode(SyncMode mode) { Mode = mode; }
public static readonly CacheMode Dynamic = new(SyncMode.Dynamic);
public static readonly CacheMode DynamicOfflineCached = new(SyncMode.DynamicOfflineCached);
public static readonly CacheMode DynamicCached = new(SyncMode.DynamicCached);
public static readonly CacheMode AlwaysReturnLocal = new(SyncMode.AlwaysReturnLocal);
public readonly SyncMode Mode;
public static implicit operator SyncMode(CacheMode value) => value.Mode;
public static explicit operator CacheMode(SyncMode value) => FromSyncMode(value);
public static CacheMode FromSyncMode(SyncMode value)
{
return value switch
{
SyncMode.AlwaysReturnLocal => CacheMode.AlwaysReturnLocal,
SyncMode.DynamicCached => CacheMode.DynamicCached,
SyncMode.DynamicOfflineCached => CacheMode.DynamicOfflineCached,
SyncMode.Dynamic => CacheMode.Dynamic,
_ => throw new InvalidCastException("SyncMode value must be Dynamic or Greater. Value passed into method: " + Enum.GetName(typeof(SyncMode), value))
};
}
public static CacheMode DefaultOrGreater(SyncMode? syncMode)
{
if (syncMode is null || syncMode == SyncMode.Dynamic) return CacheMode.Dynamic;
return FromSyncMode(Factory.NSOFactoryBase.PrioritizeSyncMode(SyncMode.Dynamic, (SyncMode)syncMode));
}
public static CacheMode DefaultOrGreater(SyncMode? syncMode, Interfaces.INetworkSyncObject networkSyncObject)
{
if (syncMode is null) return DefaultOrGreater(networkSyncObject?.SyncPriority);
var mode = NSOFactoryBase.PrioritizeSyncMode((SyncMode)syncMode, networkSyncObject?.SyncPriority ?? SyncMode.Dynamic);
return DefaultOrGreater(mode);
}
}
工廠類:
namespace NetworkSyncObjects
{
public partial class SyncedFile
{
/// <summary>
/// Factory to create <see cref="SyncedFile"/> objects. <br/>
/// This factory does not specify the <see cref="CacheMode"/>.
/// </summary>
public class SyncedFileFactory : NSOFactoryBase
{
#region < Factory Construction >
internal protected SyncedFileFactory(NSOFactorySettings factorySettings) : base(factorySettings) { }
public static SyncedFileFactory CreateFactory(NSOFactorySettings factorySettings)
{
//Validate Input
if (factorySettings is null) throw new ArgumentNullException(nameof(factorySettings));
return new SyncedFileFactory(factorySettings);
}
public static SyncedFileFactory CreateFactory(NSOFactorySettings objectToClone, string rootFolder)
{
var fS = new NSOFactorySettings(rootFolder, objectToClone);
return new SyncedFileFactory(fS);
}
#endregion
static bool PathValidation(string path, string variableName, out Exception e)
{
if (String.IsNullOrWhiteSpace(path))
{
e = new ArgumentException($"Invalid Argument: '{variableName}' is null or empty", variableName);
return true;
}
if (!PathEx.IsPathFullyQualified(path))
{
e = new ArgumentException($"Invalid Argument: '{variableName}' is not fully qualified! \nSupplied path: {path}", variableName);
return true;
}
if (!Path.HasExtension(path))
{
e = new ArgumentException($"Invalid Argument: '{variableName}' does not have a file extension! \nSupplied path: {path}", variableName);
return true;
}
if (string.IsNullOrWhiteSpace(Path.GetFileName(path)))
{
e = new ArgumentException($"Unable to retrieve filename from SourceFilePath! \n Supplied path: {path}", variableName);
return true;
}
e = null;
return false;
}
#region < Factory Methods >
#region < From Source and Destination FilePath >
public SyncedFile FromSource(string SourceFilePath, CacheMode syncMode)
{
if (PathValidation(SourceFilePath, nameof(SourceFilePath), out var E)) throw E;
string localPath = ConvertNetworkPathToLocalPath(SourceFilePath, null);
return FromSourceAndDestination(SourceFilePath, localPath, syncMode);
}
public SyncedFile FromSourceAndDestination(string SourceFilePath, string DestinationFilePath, CacheMode syncMode, string ID = null)
{
if (PathValidation(SourceFilePath, nameof(SourceFilePath), out var e)) throw e;
if (PathValidation(DestinationFilePath, nameof(DestinationFilePath), out e)) throw e;
return new SyncedFile(
networkPath: SourceFilePath,
localPath: DestinationFilePath,
iD: ID ?? "SyncedFile_" + Path.GetFileName(DestinationFilePath),
syncMode: syncMode,
this.FactorySettings
);
}
#region < Overloads >
public SyncedFile FromSourceAndDestination(string SourceFilePath, DirectoryInfo DestinationFolder, CacheMode syncMode) => FromSourceAndDestination(SourceFilePath, Path.Combine(DestinationFolder.FullName, Path.GetFileName(SourceFilePath)), syncMode);
#endregion
#region < From NetworkFolder >
/// <inheritdoc cref="SyncedFile.SyncedFile(string, INetworkFolder, CacheMode?)"/>
public SyncedFile FromNetworkFolder(string filePath, INetworkFolder parent, string iD = null) => new SyncedFile(filePath, parent, CacheMode.DefaultOrGreater(parent.SyncPriority));
#endregion
#region < From INetworkSyncDataObject >
public SyncedFile FromIConstructionData(IConstructionData_NetPathOnly dataObject)
{
if (dataObject is null) throw new ArgumentNullException(nameof(dataObject));
if (PathValidation(dataObject.NetworkPath, "dataObject.NetworkPath", out Exception e)) throw e;
string netPath = FactorySettings.GetUncPath(dataObject.NetworkPath, out MappedDrive drv);
string localPath = ConvertNetworkPathToLocalPath(dataObject.NetworkPath, drv);
return new SyncedFile(
netPath,
localPath,
dataObject.ID,
CacheMode.DefaultOrGreater(dataObject.SyncMode),
this.FactorySettings);
}
public SyncedFile FromIConstructionData(IConstructionData dataObject)
{
if (dataObject is null) throw new ArgumentNullException(nameof(dataObject));
if (PathValidation(dataObject.NetworkPath, "dataObject.NetworkPath", out Exception e)) throw e;
if (PathValidation(dataObject.LocalPath, "dataObject.LocalPath", out e)) throw e;
return new SyncedFile(
dataObject.NetworkPath,
dataObject.LocalPath,
dataObject.ID,
CacheMode.DefaultOrGreater(dataObject.SyncMode),
this.FactorySettings
);
}
#endregion
#endregion
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.