我正在努力学习模式,而且我有一份为模式而尖叫的工作,我只知道但我无法理解。我知道过滤器类型可以抽象并可能被桥接。我不是在寻找代码重写的建议。我不是在找人做我的工作。我想知道如何将模式应用于此示例。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;
using System.Xml;
using System.Text.RegularExpressions;
namespace CopyTool
{
class CopyJob
{
public enum FilterType
{ TextFilter, RegExFilter, NoFilter }
public FilterType JobFilterType { get; set; }
private string _jobName;
public string JobName { get { return _jobName; } set { _jobName = value; } }
private int currentIndex;
public int CurrentIndex { get { return currentIndex; } }
private DataSet ds;
public int MaxJobs { get { return ds.Tables["Job"].Rows.Count; } }
private string _filter;
public string Filter { get { return _filter; } set { _filter = value; } }
private string _fromFolder;
public string FromFolder
{
get { return _fromFolder; }
set
{
if (Directory.Exists(value))
{ _fromFolder = value; }
else
{ throw new DirectoryNotFoundException(String.Format("Folder not found: {0}", value)); }
}
}
private List<string> _toFolders;
public List<string> ToFolders { get { return _toFolders; } }
public CopyJob()
{
Initialize();
}
private void Initialize()
{
if (ds == null)
{ ds = new DataSet(); }
ds.ReadXml(Properties.Settings.Default.ConfigLocation);
LoadValues(0);
}
public void Execute()
{
ExecuteJob(FromFolder, _toFolders, Filter, JobFilterType);
}
public void ExecuteAll()
{
string OrigPath;
List<string> DestPaths;
string FilterText;
FilterType FilterWay;
foreach (DataRow rw in ds.Tables["Job"].Rows)
{
OrigPath = rw["FromFolder"].ToString();
FilterText = rw["FilterText"].ToString();
switch (rw["FilterType"].ToString())
{
case "TextFilter":
FilterWay = FilterType.TextFilter;
break;
case "RegExFilter":
FilterWay = FilterType.RegExFilter;
break;
default:
FilterWay = FilterType.NoFilter;
break;
}
DestPaths = new List<string>();
foreach (DataRow crw in rw.GetChildRows("Job_ToFolder"))
{
DestPaths.Add(crw["FolderPath"].ToString());
}
ExecuteJob(OrigPath, DestPaths, FilterText, FilterWay);
}
}
private void ExecuteJob(string OrigPath, List<string> DestPaths, string FilterText, FilterType FilterWay)
{
FileInfo[] files;
switch (FilterWay)
{
case FilterType.RegExFilter:
files = GetFilesByRegEx(new Regex(FilterText), OrigPath);
break;
case FilterType.TextFilter:
files = GetFilesByFilter(FilterText, OrigPath);
break;
default:
files = new DirectoryInfo(OrigPath).GetFiles();
break;
}
foreach (string fld in DestPaths)
{
CopyFiles(files, fld);
}
}
public void MoveToJob(int RecordNumber)
{
Save();
LoadValues(RecordNumber - 1);
}
public void AddToFolder(string folderPath)
{
if (Directory.Exists(folderPath))
{ _toFolders.Add(folderPath); }
else
{ throw new DirectoryNotFoundException(String.Format("Folder not found: {0}", folderPath)); }
}
public void DeleteToFolder(int index)
{
_toFolders.RemoveAt(index);
}
public void Save()
{
DataRow rw = ds.Tables["Job"].Rows[currentIndex];
rw["JobName"] = _jobName;
rw["FromFolder"] = _fromFolder;
rw["FilterText"] = _filter;
switch (JobFilterType)
{
case FilterType.RegExFilter:
rw["FilterType"] = "RegExFilter";
break;
case FilterType.TextFilter:
rw["FilterType"] = "TextFilter";
break;
default:
rw["FilterType"] = "NoFilter";
break;
}
DataRow[] ToFolderRows = ds.Tables["Job"].Rows[currentIndex].GetChildRows("Job_ToFolder");
for (int i = 0; i <= ToFolderRows.GetUpperBound(0); i++)
{
ToFolderRows[i].Delete();
}
foreach (string fld in _toFolders)
{
DataRow ToFolderRow = ds.Tables["ToFolder"].NewRow();
ToFolderRow["JobId"] = ds.Tables["Job"].Rows[currentIndex]["JobId"];
ToFolderRow["Job_Id"] = ds.Tables["Job"].Rows[currentIndex]["Job_Id"];
ToFolderRow["FolderPath"] = fld;
ds.Tables["ToFolder"].Rows.Add(ToFolderRow);
}
}
public void Delete()
{
ds.Tables["Job"].Rows.RemoveAt(currentIndex);
LoadValues(currentIndex++);
}
public void MoveNext()
{
Save();
currentIndex++;
LoadValues(currentIndex);
}
public void MovePrevious()
{
Save();
currentIndex--;
LoadValues(currentIndex);
}
public void MoveFirst()
{
Save();
LoadValues(0);
}
public void MoveLast()
{
Save();
LoadValues(ds.Tables["Job"].Rows.Count - 1);
}
public void CreateNew()
{
Save();
int MaxJobId = 0;
Int32.TryParse(ds.Tables["Job"].Compute("Max(JobId)", "").ToString(), out MaxJobId);
DataRow rw = ds.Tables["Job"].NewRow();
rw["JobId"] = MaxJobId + 1;
ds.Tables["Job"].Rows.Add(rw);
LoadValues(ds.Tables["Job"].Rows.IndexOf(rw));
}
public void Commit()
{
Save();
ds.WriteXml(Properties.Settings.Default.ConfigLocation);
}
private void LoadValues(int index)
{
if (index > ds.Tables["Job"].Rows.Count - 1)
{ currentIndex = ds.Tables["Job"].Rows.Count - 1; }
else if (index < 0)
{ currentIndex = 0; }
else
{ currentIndex = index; }
DataRow rw = ds.Tables["Job"].Rows[currentIndex];
_jobName = rw["JobName"].ToString();
_fromFolder = rw["FromFolder"].ToString();
_filter = rw["FilterText"].ToString();
switch (rw["FilterType"].ToString())
{
case "TextFilter":
JobFilterType = FilterType.TextFilter;
break;
case "RegExFilter":
JobFilterType = FilterType.RegExFilter;
break;
default:
JobFilterType = FilterType.NoFilter;
break;
}
if (_toFolders == null)
_toFolders = new List<string>();
_toFolders.Clear();
foreach (DataRow crw in rw.GetChildRows("Job_ToFolder"))
{
AddToFolder(crw["FolderPath"].ToString());
}
}
private static FileInfo[] GetFilesByRegEx(Regex rgx, string locPath)
{
DirectoryInfo d = new DirectoryInfo(locPath);
FileInfo[] fullFileList = d.GetFiles();
List<FileInfo> filteredList = new List<FileInfo>();
foreach (FileInfo fi in fullFileList)
{
if (rgx.IsMatch(fi.Name))
{
filteredList.Add(fi);
}
}
return filteredList.ToArray();
}
private static FileInfo[] GetFilesByFilter(string filter, string locPath)
{
DirectoryInfo d = new DirectoryInfo(locPath);
FileInfo[] fi = d.GetFiles(filter);
return fi;
}
private void CopyFiles(FileInfo[] files, string destPath)
{
foreach (FileInfo fi in files)
{
bool success = false;
int i = 0;
string copyToName = fi.Name;
string copyToExt = fi.Extension;
string copyToNameWithoutExt = Path.GetFileNameWithoutExtension(fi.FullName);
while (!success && i < 100)
{
i++;
try
{
if (File.Exists(Path.Combine(destPath, copyToName)))
throw new CopyFileExistsException();
File.Copy(fi.FullName, Path.Combine(destPath, copyToName));
success = true;
}
catch (CopyFileExistsException ex)
{
copyToName = String.Format("{0} ({1}){2}", copyToNameWithoutExt, i, copyToExt);
}
}
}
}
}
public class CopyFileExistsException : Exception
{
public string Message;
}
}
答案 0 :(得分:6)
此代码也“尖叫”,可以分解为更小的更专业的对象。
您的CopyJob对象似乎更像是作业列表的管理者。我可能会将此名称更改为CopyJobManager或其他东西。然后,您可以将CopyJob作为不同过滤器类型的基类。例如,公共代码Execute()将在基类中定义,并且自定义行为(例如,Filtering)将在派生类中处理。你会有一个TextFilterCopyJob,一个RegExFilterCopyJob和一个NoFilterCopyJob。
工厂模式可以发挥作用的是你正在构建一个CopyJobs列表。您可以拥有一个CopyJobFactory对象,该对象从您的数据集中获取一行并返回CopyJob的正确子版本。然后,CopyJobManager将在CopyJobs列表上执行操作,而不是数据集行列表。
答案 1 :(得分:1)
每当我看到Swithcs或者Ifs的砖块时,我都会得出结论,即至少可以创建一个策略模式。
设置一个简洁明了的方法是使用字典&lt;&gt;
在您的情况下,您将需要基于您的案例所涉及的filterName的键值,并且该值将是过滤器的新对象。
现在你只需将字符串赋予dictionarys TryGetValue方法并让它为你检索正确的过滤器对象,繁荣!
现在,您可以封装过滤器的映射&lt; - &gt;字符串,并保持过滤器的逻辑和使用不必看到检索正确对象的逻辑!
答案 2 :(得分:0)
使用像你这样的switch语句没有任何问题。除了你可以将它放在一个函数中以便你没有两次相同的开关之外,任何设计模式都不会尖叫。
开关将比使用反射更快,而您尝试解决的问题实际上并不需要工厂模式。
答案 3 :(得分:0)
以下是我为实现工厂模式所做的一些工作
首先,我为过滤器创建了一个界面:
interface IFileFilter
{
string GetFilterName();
string GetFilterReadableName();
FileInfo[] GetFilteredFiles(string path, string filter);
}
然后我为这个接口创建了子过滤器类:
class RegExFileFilter : IFileFilter
{
#region IFileFilter Members
public string GetFilterName()
{
return "RegExFilter";
}
public string GetFilterReadableName()
{
return "RegEx Filter";
}
public FileInfo[] GetFilteredFiles(string path, string filter)
{
DirectoryInfo d = new DirectoryInfo(path);
FileInfo[] fullFileList = d.GetFiles();
List<FileInfo> filteredList = new List<FileInfo>();
Regex rgx = new Regex(filter);
foreach (FileInfo fi in fullFileList)
{
if (rgx.IsMatch(fi.Name))
{
filteredList.Add(fi);
}
}
return filteredList.ToArray();
}
#endregion
}
class TextFileFilter : IFileFilter
{
#region IFileFilter Members
public string GetFilterName()
{
return "TextFilter";
}
public string GetFilterReadableName()
{
return "Text Filter";
}
public FileInfo[] GetFilteredFiles(string path, string filter)
{
DirectoryInfo d = new DirectoryInfo(path);
FileInfo[] fi = d.GetFiles(filter);
return fi;
}
#endregion
}
class NoFileFilter : IFileFilter
{
#region IFileFilter Members
public string GetFilterName()
{
return "TextFilter";
}
public string GetFilterReadableName()
{
return "Text Filter";
}
public FileInfo[] GetFilteredFiles(string path, string filter)
{
DirectoryInfo d = new DirectoryInfo(path);
FileInfo[] fi = d.GetFiles(filter);
return fi;
}
#endregion
}
然后我创建了一个工厂:
public static IFileFilter FileFilter(string filterName)
{
switch (filterName)
{
case "Text Filter":
return new TextFileFilter();
case "RegEx Filter":
return new RegExFileFilter();
default:
return new NoFileFilter();
}
}
答案 4 :(得分:0)
我建议如下:
重构switch语句(如@Jordan提到的)
添加扩展方法以将FilterType枚举转换为int并将其保存到数据库而不是字符串。 E.g。
public static class FilterTypeExtensions
{
public static int AsNumeric(this FilterType filterType)
{
return (int)filterType;
}
}
作为一个小问题,单线支撑是可怕的,要么放下牙箍,要么使用适当的间距/缩进。 :)