我应该如何编写工厂类 - 生成派生的对象

发布于 2025-01-23 10:53:10 字数 5430 浏览 4 评论 0原文

首先,我将布置我的一般设置并描述类的目标,因为我认为这对于一个问题很重要:

  • 这旨在根据应用程序需要动态缓存文件和文件夹。
  • 如果用户需要将它们复制到某个地方,则可以复制本地版本,而不是每次下载遥控器。相反,只有在可用的文件/文件夹更新时才下载。 (对于文件夹,这是通过Robocopy Rigroner执行的)
  • 此外,对这里的文字墙感到抱歉
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);
     }  
}  

,因此它很有趣:

  • 我要为此设置的工厂将包含FileOps对象,因此消费者不必必须在构造函数中不断地指定它 - 工厂将为他们做。
  • 网络文件夹中存在一个SyncedFile(但不一定在该文件夹中,而是在子文件夹路径中),因此SyncedFileFactory必须包含一种使用该父级创建对象的方法。同样的原理适用于同步固定器
  • SyncedFile和SyncedFolder都期望永远不会使用“ EnswaysRoturnnetwork”枚举值。这就是为什么我想使用工厂方法,以确保该值永远不会传递到CTOR中,因为这些对象处于该状态是没有意义的。
  • 还有一个我允许从中创建对象的界面。这样,消费者可以从数据库(或我的情况下是Excel文件)中读取一些实现接口的对象,然后将其传递到工厂以构造对象。

这是问题:

  • 我的计划是拥有SyncedFileFactoryNetworkFolderFactorySyncedfolderFactory

    • 但是,既然我已经写出来了,我只能评估SyncMode并从NetworkFolderFactory返回SynceDFolder或NetworkFolder。这是足够容易理解的,还是我应该拥有自己的工厂以清楚建筑?
    • 请注意,我最初没有想到这个问题,因此我以下问题:
  • 拥有将其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构造的对象时,我们会遇到一些问题,我遇到了一些问题,我' m不确定在使用该接口时保持工厂结构清除(强制指定SyncMode)时,最佳方法可以使工厂结构保持清晰

  • ,尚不清楚应该发生什么。 (它使用接口指定的SyncMode或工厂的SyncMode?)
  • 使用父网络折叠对象生成它时的同一问题。
    • 但是,如果网络折叠符对象是“ ewerning returnnetwork”,那么SyncedFile和SyncedFolder不应继承它

:可能的解决方案 - 需要思考:

因此,现在我的思维方式本质上是:

  • Offlinecache应该优先考虑localcache,用于施工,但是ewlboyturnlocal是施工的最高优先级。那么,我是否只是简单地评估输入父母和所选工厂并采取相应行动?那可能是最简单的事情。但是,如果有人去看它,您将与输入值不同的输出值结束。这种交互降低了清晰度,但与库的预期功能保持一致。

To start, I'll lay out my general setup and describe the goal of the classes, as I feel its important for the question:

  • This is designed to dynamically cache files and folders as needed by the application.
  • If the user needs to copy them somewhere, this allows them to copy the local version instead of downloading off the remote every single time. Instead, it will only download if an update to the file/folder is available. (For folders, this is performed with robocopy mirroring)
  • Also, sorry for wall of text here
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);
     }  
}  

So here is where it gets fun:

  • The factories I want to set up for this will contain the FileOps object so that the consumer doesn't have to constantly specify it in the constructor - the factory will do it for them.
  • A SyncedFile exists within a NetworkFolder(but not necessarily in that folder, but maybe in a subfolder path), so the SyncedFileFactory must contain a method to create a object using that parent. This same principle applies to SyncedFolder
  • SyncedFile and SyncedFolder both expect to never use the 'AlwaysReturnNetwork' enum value. This is partly why I wanted to use a factory method, to ensure that value is never passed into the CTOR, as it doesn't make sense for those objects to be in that state.
  • There also exists an interface I'm allowing creation of the object from. This way, a consumer can read data from a database (or in my case an excel file) into some object that implements the interface, which can then be passed into the factory to construct the object.

Heres are questions:

  • My plan is to have a SyncedFileFactory, a NetworkFolderFactory, and a SyncedFolderFactory

    • But, now that I've written that out, I could just evaluate the SyncMode and return either a SyncedFolder OR NetworkFolder from the NetworkFolderFactory. Is this the easy enough to understand, or should I have its own factory for clarity of construction?
    • Note that I didn't think of this originally due to my question below:
  • Does it make sense to have a factory that applies its SyncMode to the class being constructed? Or a more generic Factory that simply validates the SyncMode passed into the method?

Here is what I have at the moment:

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

I like that this enforces the types of SyncModes and only constructs objects with valid sync modes, but when constructing from an object that already has a syncMode specified, we run into a few issues, and I'm unsure the best way to work around this while keeping factory structure clear

  • when using the interface (which enforces specifying a SyncMode), it becomes unclear what should happen. (Does it use the SyncMode specified by the interface, or the SyncMode of the factory?)
  • Same issue for when generating it using a parent NetworkFolder object.
    • But if the NetworkFolder object is 'AlwaysReturnNetwork', then SyncedFile and SyncedFolder should not inherit it anyway

Edit: Possible Solution - Need Thoughts on this:

So now my line of thinking is essentially:

  • OfflineCache should take priority over LocalCache, for construction, but AlwaysReturnLocal is highest priority for construction. So Do I simply evaluate the input parent and the chosen factory and act accordingly? That might be the easiest thing to do. But if someone goes to look at it, you wind up with the output value differing from the input value. That interaction reduces clarity, but keeps in line with intended function of the library.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

她如夕阳 2025-01-30 10:53:10

好的,因此,当我继续开发此DLL时,我遇到了其他一些问题。我将为下面的其他人详细介绍可能受到启发的任何人。

原始思考过程:创建每个SyncMode类型的工厂(至少是主要值)。
我想到的原因是:

  • 某些类型没有意义 /无法具有某些价值。示例:SyncedFile绝不应该是“始终归功于”。该类的全部要点是它在本地缓存了一个文件,因此允许永远不会返回本地路径是没有意义的。

此问题:

  • 需要实例化的工厂对象过多,
  • 默认情况下某些方法继承了该值,而不是使用特定于工厂的方法。 (创建一个驻留在同步文件中的SyncedFile,继承了SyncedFolder的枚举值)

原始计划:具有一个全局设置对象,该库是指定义func< bool>是否确定应用程序是否确定应用程序的目标。是否处于离线模式,是否允许本地缓存等。
此问题:

  • 这样的全球定义对象对于一个独立的应用程序就可以了。但是,要变得更好,更灵活,如果需要,则应该能够定制每个对象的目标目标。

解决方案:

  • 将用于全局设置的静态类转换为对象类。如果需要,该应用程序可以具有单个设置对象,或者在需要时具有多个。
  • 出厂对象将新的NsofactorySettings对象带有其构造函数。 (基类现在具有类型nsofactorySettings的属性。所有派生类都指向此属性,而不是静态类。)
  • 工厂方法已被重写为更通用,将枚举作为参数而不是依靠工厂的枚举价值。 (可能有6个工厂减少到1。此外,更清洁,更清晰的工厂代码是此更改的结果。)
  • 为了强制执行传递给构造函数的枚举类型,我创建了一种新的结构类型,其基本值是枚举类型的。然后只允许静态引用。

用于执行特定枚举的结构:

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

OK, so as I continued to develop this dll, i ran into some other issues that have since been worked out. I'll detail my resolution to this below for anyone else that may be inspired.

Original Thought Process: Create a factory of each SyncMode type (atleast the primary values).
Reason I thought of wanted it:

  • Some types don't make sense / cant have certain values. Example: SyncedFile should never be 'AlwaysReturnNetwork'. The whole point of that class is that it gets a file cached locally, so to allow never returning of the local path doesn't make sense.

Problems with this:

  • Too many factory objects need to be instantiated
  • Some methods inherit the value by default instead of using the factory-specific one. (Creating a SyncedFile that resides within a SyncedFolder inherits the SyncedFolder's enum value)

Original Plans: Have a global settings object the library refers to that takes care of defining the Func<bool> targets that determine if the application is in offline mode, whether to allow local caching, etc.
Problems with this:

  • A globally defined object like this is fine for a self-contained app. But to be better and more flexible, the func targets should be able to be customized per object if need be.

Solutions:

  • Convert the static class used for global settings into an object class. This allows the app to have a single settings object if desired, or have multiple if needed.
  • Factory Objects take the new NSOFactorySettings object in their constructor. ( base class now has property of type NSOFactorySettings. All derived classes now point to this property instead of the static class.)
  • Factory methods have been rewritten to be more generic, accepting the enum as a parameter instead of relying on the factory's enum value. ( potentially 6 factories reduced to 1. Also, much cleaner and clearer factory code was the result of this change. )
  • To enforce the types of enum being passed to a constructor, i created a new Struct type whose underlying value is of the enum type. Then only allow static reference to it.

Struct used for enforcing specific enums:

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

Factory Class:

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(
quot;Invalid Argument: '{variableName}' is null or empty", variableName);
                    return true;
                }
                if (!PathEx.IsPathFullyQualified(path))
                {
                    e = new ArgumentException(
quot;Invalid Argument: '{variableName}' is not fully qualified! \nSupplied path: {path}", variableName);
                    return true;
                }
                if (!Path.HasExtension(path))
                {
                    e = new ArgumentException(
quot;Invalid Argument: '{variableName}' does not have a file extension! \nSupplied path: {path}", variableName);
                    return true;
                }
                if (string.IsNullOrWhiteSpace(Path.GetFileName(path)))
                {
                    e = new ArgumentException(
quot;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
        }
}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文