先分析一下,文件名管理系统分为哪几个部分,
初步分析是界面(即client),和文件名处理两个部分,那么client不应该出现文件名的处理的,
(但是界面逻辑可以保留下来,比如点击"启用编号"就将相应的选项打开)
因此,可以先尝试着抽象出一个文件名处理类,
命名为FileNameManager吧,此类的主要功能是完成:
1 在输入文件完整路径后(以字符串数组形式),然后加载改文件到相应的List对象中,
2 将List中的对象进行改名(只考虑批量更改的情况)
在其中定义两个功能的函数来处理就行
而客户端则可以声明一个FileNameManager来处理它的需求
基于此可以画出类图
对于文件名管理器而言,它并不需要知道客户端的存在,而客户端需要知道文件名管理器,因为需要它来管理自己的文件名,因此他们之间是关联的关系
整个类代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class FileNameManager
{
private List<FileInfo> curAddedFiles; //当前添加的文件
private FileInfo curFileInf; //当前文件
/// <summary>
/// 初始化文件名管理类
/// </summary>
/// <param name="curAddedFiles">当前添加的文件</param>
/// <param name="curFileInf">当前选择文件</param>
public FileNameManager(List<FileInfo> curAddedFiles, FileInfo curFileInf)
{
this.curAddedFiles = curAddedFiles;
this.curFileInf = curFileInf;
}
/// <summary>
/// 添加文件(按文件名数组)
/// </summary>
/// <param name="files"></param>
public void AddFiles(string[] files)
{
try
{
for (int i = 0; i < files.Length; i++)
{
//判断当前列表中是否已经存在该文件信息
if (!curAddedFiles.Contains(new FileInfo(files[i])))
{
curAddedFiles.Add(new FileInfo(files[i]));
}
}
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 添加文件(按文件信息对象)
/// </summary>
/// <param name="files"></param>
public void AddFiles(FileInfo[] files)
{
try
{
for (int i = 0; i < files.Length; i++)
{
//判断当前列表中是否已经存在该文件信息
if (!curAddedFiles.Contains(files[i]))
{
curAddedFiles.Add(files[i]);
}
}
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 添加文件(按目录对象)
/// </summary>
/// <param name="files"></param>
public void AddFiles(DirectoryInfo directory)
{
try
{
FileInfo[] tmpFileInfos = directory.GetFiles();
foreach (var item in tmpFileInfos)
{
if (!curAddedFiles.Contains(item))
{
curAddedFiles.Add(item);
}
}
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 为文件改名
/// </summary>
/// <param name="changingMethod">改名方式(前缀,后缀)</param>
/// <param name="digits">位数</param>
/// <param name="filename">以此为基础改名</param>
public void ChangeNames(string changingMethod, int digits, string filename)
{
if (curAddedFiles == null || curAddedFiles.Count == 0)
{
throw new Exception("还没有添加任何文件!");
}
string setDigit = "";
for (int i = 0; i < digits; i++)
{
setDigit += "0";
}
switch (changingMethod)
{
//以前缀形式添加
case "Prefix":
for (int i = 0; i < curAddedFiles.Count; i++)
{
curAddedFiles[i].MoveTo(curFileInf.DirectoryName + "\\" +
string.Format("{0:" + setDigit + "} ", i) + filename + curFileInf.Extension);
//↑ 拼接一段格式化字符串 比如如果你设置的是两位那么拼接的结果就是 ("{0:00"} ", i) 那么文件名也将显示为 01,02,下同
}
break;
//以后缀形式添加
case "Postfix":
for (int i = 0; i < curAddedFiles.Count; i++)
{
string name = curFileInf.DirectoryName + "\\" + filename +
string.Format(" {0:" + setDigit + "}", i) + curFileInf.Extension;
curAddedFiles[i].MoveTo(name);
}
break;
default:
break;
}
}
/// <summary>
/// 格式化文件大小
/// </summary>
/// <param name="fileSize">文件大小</param>
/// <returns>格式化后的文件大小</returns>
public static String FormatFileSize(Int64 fileSize)
{
if (fileSize < 0)
{
throw new ArgumentOutOfRangeException("fileSize");
}
else if (fileSize >= 1024 * 1024 * 1024)
{
return string.Format("{0:########0.00} GB", ((Double)fileSize) / (1024 * 1024 * 1024));
}
else if (fileSize >= 1024 * 1024)
{
return string.Format("{0:####0.00} MB", ((Double)fileSize) / (1024 * 1024));
}
else if (fileSize >= 1024)
{
return string.Format("{0:####0.00} KB", ((Double)fileSize) / 1024);
}
else
{
return string.Format("{0} bytes", fileSize);
}
}
}
完成了文件名管理这个类,界面处理逻辑就要清晰的多了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
System.Windows.Forms.FolderBrowserDialog fbd = new System.Windows.Forms.FolderBrowserDialog();
OpenFileDialog ofd = new OpenFileDialog();
/*把它们俩作为成员变量的好处是在整个窗口运行期间,都会保存该选定的文件和添加的文件的状态,如果是局部变量我就要不停的获取状态*/
private List<FileInfo> curSelectedFiles = new List<FileInfo>(); //当前选定的文件
private List<FileInfo> curAddedFiles = new List<FileInfo>(); //当前添加的文件
FileNameManager fnm;
...
//打开文件
private void btnOpen_Click(object sender, RoutedEventArgs e)
{
ofd.Multiselect = true;
if (ofd.ShowDialog() == true)
{
fnm.AddFiles(ofd.FileNames);
lstFilelist.Items.Refresh();
lstFilelist.ItemsSource = curAddedFiles;
lstFilelist.DisplayMemberPath = "Name";
}
}
//打开文件夹
private void button1_Click(object sender, RoutedEventArgs e)
{
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
DirectoryInfo di = new DirectoryInfo(fbd.SelectedPath);
fnm.AddFiles(di);
}
lstFilelist.Items.Refresh();//注意,必须要重新创建视图。否则不会在该listbox中显示新的数据源
lstFilelist.ItemsSource = curAddedFiles;
lstFilelist.DisplayMemberPath = "Name";
}
...
//更改一个文件
private void btnSingle_Click(object sender, RoutedEventArgs e)
{
if (fnm.CurFileInf == null)
{
MessageBox.Show("您还没有选定一个文件!请先选择!");
return;
}
fnm.CurFileInf.MoveTo(fnm.CurFileInf.DirectoryName + "\\" + txtFileName.Text + fnm.CurFileInf.Extension);
}
//批量更改
private void btnBatch_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(txtFileName.Text))
{
MessageBox.Show("请先指定一个文件名");
return;
}
if (MessageBox.Show("该功能将以您输入的文件名为标准 为所选定的文件加上您指定的前缀或后缀","注意!",MessageBoxButton.YesNo)==MessageBoxResult.No)
{
return;
}
fnm.ChangeNames(rdoPrefix.IsEnabled ? "Prefix" : "Postfix",
Convert.ToInt32( txtDigit.Text), txtFileName.Text);
}
...
完成了之后也就完成了功能和界面的解耦,
但是依然存在很多问题,
首先,除了抽象出一个类以外,并没有使用任何其他面向对象的知识或者是设计模式
如果我要为filenameManager添加功能的话必须要修改此类
因此这就不满足"开放-封闭"的原则,
当然这样的文件名管理类的不满足单一职责原则,因为此类完成了好几个功能.
其次,该类的设计同样没有按照依赖倒转的原则(即依赖抽象)来设计--只有一个类何来抽象?
这样的设计显然是非常失败的.
下周继续重构~~~