桥梁或工厂和如何

时间:2010-06-16 19:40:24

标签: c# design-patterns

我正在努力学习模式,而且我有一份为模式而尖叫的工作,我只知道但我无法理解。我知道过滤器类型可以抽象并可能被桥接。我不是在寻找代码重写的建议。我不是在找人做我的工作。我想知道如何将模式应用于此示例。

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

}

5 个答案:

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

作为一个小问题,单线支撑是可怕的,要么放下牙箍,要么使用适当的间距/缩进。 :)