C#建造商设计
我有一个类,你在一个文件夹中传递它,然后它会关闭并处理指定文件夹中的大量数据 例如:C#建造商设计,c#,constructor,C#,Constructor,我有一个类,你在一个文件夹中传递它,然后它会关闭并处理指定文件夹中的大量数据 例如: MyClass myClass = new MyClass(@"C:\temp"); 现在它开始读取数千个文件,并用数据填充类 我是否应该将这些数据从构造函数中移出,并将其作为一个单独的方法,例如下面的方法 MyClass myClass = new MyClass(); myClass.LoadFromDirectory(@"C:\temp"); 你们班就这么做吗?如果是这样的话,我会说这并不重要。但很可
MyClass myClass = new MyClass(@"C:\temp");
现在它开始读取数千个文件,并用数据填充类
我是否应该将这些数据从构造函数中移出,并将其作为一个单独的方法,例如下面的方法
MyClass myClass = new MyClass();
myClass.LoadFromDirectory(@"C:\temp");
你们班就这么做吗?如果是这样的话,我会说这并不重要。但很可能你们的班级实际上做的比你们展示的要多。例如,它是否有任何错误处理 构造函数的目的是构造一个对象。方法的目的是执行操作。因此,我投票支持这种形式:
MyClass myClass = new MyClass();
myClass.LoadFromDirectory(@"C:\temp");
视情况而定。你应该评估课程的基本目的。它有什么功能 我通常更喜欢的是让类构造函数进行类运行所需的初始化。然后我调用类上的方法,该类可以安全地假定必要的初始化已经完成 通常,初始化阶段不应过于密集。执行上述操作的另一种方法可能是:
// Instantiate the class and get ready to load data from files.
MyClass myClass = new MyClass(@"C:\temp");
// Parse the file collection and load necessary data.
myClass.PopulateData();
也许您应该用一个返回对象实例的静态方法来尝试这种方法
var myClass = MyClass.LoadFromDirectory(@"C:\temp");
这将使初始化代码保持在构造函数之外,并为您提供所需的“一行”声明
在海报下面的评论中,通过添加状态,实现可以如下所示:
public class MyClass
{
#region Constructors
public MyClass(string directory)
{
this.Directory = directory;
}
#endregion
#region Properties
public MyClassState State {get;private set;}
private string _directory;
public string Directory
{
get { return _directory;}
private set
{
_directory = value;
if (string.IsNullOrEmpty(value))
this.State = MyClassState.Unknown;
else
this.State = MyClassState.Initialized;
}
}
#endregion
public void LoadFromDirectory()
{
if (this.State != MyClassState.Initialized || this.State != MyClassState.Loaded)
throw new InvalidStateException();
// Do loading
this.State = MyClassState.Loaded;
}
}
public class InvalidStateException : Exception {}
public enum MyClassState
{
Unknown,
Initialized,
Loaded
}
我认为您应该根据是否计划重用同一对象在不同的输入上执行相同的操作来决定上述两种方法(“首先初始化,然后执行”vs“empty init,使用params执行”)。
如果该类仅用于在固定参数上运行任务,我会在构造函数中初始化它(使其为只读偶数),然后在其他方法上执行任务。
如果您想继续在不同的参数上执行任务,我会将其放在task方法本身中
如果所有的类都是这个任务,我也会考虑把它变成一个静态的类/方法——它不需要保持它的内部状态。
无论如何,我永远不会把任务本身放在构造函数中。正如Cerburus所说,初始化应该很快。除非类的主要目的是执行I/O,否则您可能不应该在构造函数中执行I/O(可能引发IOException) 考虑将类分成两部分:
interface IMyDataSource
{
// ...
}
class FileDataSource: IMyDataSource
{
public FileDataSource(string path)
{
// ...
}
}
class MyClass
{
public MyClass(IMyDataSource source)
{
// ...
}
}
IMyDataSource myDS = new FileDataSource(@"C:\temp");
MyClass myClass = new MyClass(myDS);
这样,主类可以专注于管理自己的状态,而数据源则从文件内容构建初始状态。如果这是类使用的唯一资源,那么最好将路径传递给构造函数。否则,它将成为类成员的一个参数。我个人倾向于使用C#3.0初始值设定项
class MyClass {
public string directory;
public void Load() {
// Load files from the current directory
}
}
MyClass myClass = new MyClass{ directory = @"C:\temp" };
myClass.Load();
这有几个优点:
- 对象实例化将没有 自动文件系统的副作用
- 所有参数都已命名
- 所有参数都是可选的(但是, 当然,我可以扔一个 Load()中的异常(如果未定义)
- 可以初始化任意数量的属性 希望在实例化调用中 而不必使系统过载 构造器。例如,选项 对于是否递归目录, 或用于filespec搜索的通配符 因为
- 你仍然可以有一些逻辑 在setter中为目录做什么 一些东西,但同样,副作用 这通常不是一件好事
- 通过在 单独的过程调用,您可以避免 不能够 在中引用myClass实例 异常处理程序
在我看来,这似乎比“构造函数应该创建对象并从文件系统加载其数据”更符合逻辑。我同意Ari和其他人的观点——将它们分开 构造器应该真正完成最少的工作(只需初始化对象以备使用,并保持不变)。通过使用单独的方法完成工作:
- 调用方更清楚的是,worker函数可能需要很长时间
- 可以很容易地提供几个构造函数来初始化具有不同信息的对象(例如,您可以传入自己的类(而不是字符串)也可以传入一个额外的参数,指定要匹配的通配符文件名,或一个标志,指定搜索是否应递归到子文件夹)
- 您可以避免构造函数出现任何问题。在构造函数中,对象的格式不完全,因此执行工作可能会很危险-例如,在构造函数中调用虚拟函数是一个非常糟糕的想法。在构造函数中输入的代码越少,意外执行“坏”操作的可能性就越小
- 将不同的行为/功能分离到不同的方法中是一种更干净的编码方式。保持初始化和工作分离
- 将来,拆分类将更易于维护和重构