热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用简单工厂写一个可复用的批量文件修改工具

前段日子忙活站点Theme的更改,到发布的时候有个问题难住了我,我要修改四十多个Theme的配置文件,这些配置文件也不在一处,整理出来打包很麻烦,而且本地环境和生产环境里面很多配置都不相同,不能通过简

前段日子忙活站点Theme的更改,到发布的时候有个问题难住了我,我要修改四十多个Theme的配置文件,这些配置文件也不在一处,整理出来打包很麻烦,而且本地环境和生产环境里面很多配置都不相同,不能通过简单把全部文件粘贴过去这种方式替换生产环境的配置文件,只能去修改,后来频繁的修改Theme,终于意识到要写个工具了,之前也有一些修改文件的工具,但都是各行其是,痛定思痛决定写一个可复用的批量文件修改工具,当然本文的重点并不在于怎么查找、修改文件,而在于怎么复用。

最开始编程的时候听说过设计模式,急不可耐的读了一番,说实话几乎没有收获,不明白为什么要用设计模式,工作两年后再读设计模式,不敢说收获有多大,但是重构了很多以前的代码,感觉不错,后来自己就情不自禁的在使用一些设计模式了,这个简单的小工具,工厂模式又帮了大忙

需求

我希望做出来的效果是这样的

image

1. 可以在某个文件夹下搜索文件,而不是检索整个硬盘(这个是当然)

2. 不仅仅是按照文件全名搜索,还可以使用一些通配符

3. 能够自己决定是否搜索子文件夹

这些都是框架部分,至于怎么去修改文件,肯定只有开发者自己知道,所以这个工具还得有开发者在框架下不影响其它算法,而拓展自己所需算法的功能。也就是说当我想批量修改某些文件的时候我可以仅仅写一个如何修改文件的算法,而不用关注与怎么搜索神马的,同时拓展部分还不能影响其它算法。

基础框架

需求其实很简单,看看怎么实现,我做的solution目录结构是这样的

image

FileUtility.cs

Base文件夹下的FileUtility.cs封装了搜索文件的方法,写的不太好,凑活能用

public class FileUtility
    {
        public static List<string> GetAllFiles(string path, string pattern, bool searchChildFolder)
        {
            List<string> names = new List<string>();
            DirectoryInfo di = new DirectoryInfo(path);

            if (!searchChildFolder)
            {
                FileInfo[] fis = di.GetFiles(pattern);
                foreach (FileInfo fi in fis)
                {
                    names.Add(fi.FullName);
                }
            }
            else
            {
                GetFile(path, pattern, names);
            }
            return names;
        }

        public static void GetFile(string path, string pattern, List<string> names)
        {
            DirectoryInfo di = new DirectoryInfo(path);
            string[] patterns=pattern.Split(new char[]{'|',','},StringSplitOptions.RemoveEmptyEntries);
            foreach (string p in patterns)
            {
                FileInfo[] fis = di.GetFiles(p.Trim());
                foreach (FileInfo fi in fis)
                {
                    names.Add(fi.FullName);
                }
            }

            DirectoryInfo[] dis = di.GetDirectories();
            if (dis.Length != 0)
            {
                foreach (DirectoryInfo _di in dis)
                {
                    GetFile(_di.FullName, pattern, names);
                }
            }
        }
    }

Algorithm

Algorithm 这个project Assembly name 是SSTool.Algorithm,存放所有修改文件的算法,Base文件夹下的IAlgorithm是所有算法都要实现的接口

public interface IAlgorithm
    {
        void execute(List<string> files);
    }

DemoAlgorithem.cs是一个简单的示例算法,文件内写一行数据

public class DemoAlgorithem:IAlgorithm
    {

        public void execute(List<string> files)
        {
            foreach (string path in files)
            {
                using (StreamWriter sw = new StreamWriter(path, false))
                {
                    sw.WriteLine("This is a text.");
                }
            }
        }
    }

 

每添加一个算法就需要在AlgorithmConf.xml添加一条记录

xml version="1.0" encoding="utf-8" ?>
<algorithms>
    <item key="Demo" algorithm="SSTool.Algorithm.DemoAlgorithem" />
algorithms>

这是为后面工厂模式反射获取所有算法做准备

ArithmeticFactory.cs

这个是算法的工产类,用于生成算法对象实例,也就是工厂模式中的工厂类了,IAlgorithm是产品类接口,而DemoAlgorithem是一个具体产品,看看怎么生产算法产品吧

我使用了反射的方式获取算法实例,代码很简单

public IAlgorithm CreateUpdateAlgorithm(string key)
        {
            Assembly assembly = Assembly.Load("SSTool.Algorithm");
            Dictionary<string, string> map = GetConf("AlgorithmConf.xml");
            IAlgorithm algorithm = (IAlgorithm)assembly.CreateInstance(map[key]);
            return algorithm;
        }

        public Dictionary<string, string> GetConf(string path)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load("AlgorithmConf.xml");
            XmlNodeList nodes = doc.SelectNodes("//item");
            Dictionary<string, string> map = new Dictionary<string, string>();
            foreach (XmlNode node in nodes)
            {
                map.Add(node.Attributes["key"].Value, node.Attributes["algorithm"].Value);
            }
            return map;
        }

 

MainFrame.cs

MainFrame.cs用于生成外观及响应事件

为类添加一个属性,用于获取工厂实例

private ArithmeticFactory factory;
        public ArithmeticFactory Factory
        {
            get
            {
                if (factory != null)
                {
                    return factory;
                }
                else
                {
                    factory = new ArithmeticFactory();
                    return factory;
                }
            }
        }

在Load事件处理程序中使用工厂的GetConf获取所有配置,把key绑定到界面选择算法的Combobox中

protected override void OnLoad(EventArgs e)
        {
            Dictionary<string, string> map = Factory.GetConf("AlgorithmConf.xml");
            this.cmbArithmetic.Items.Clear();
            foreach (KeyValuePair<string, string> pair in map)
            {
                this.cmbArithmetic.Items.Add(pair.Key);
            }
            base.OnLoad(e);
        }

 

按钮

1.点击 “Select”按钮的时候调出选择文件夹窗口

private void btnSelect_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();
            dialog.Description = "Select Folder Path";
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                this.txtPath.Text = dialog.SelectedPath;
            }
        }

2. 点击 “Search” 按钮的时候根据文件夹及Search pattern 搜索文件列表并显示在下面列表中

dgvFiles.Columns.Clear();
            List<string> names = FileUtility.GetAllFiles(this.txtPath.Text, this.txtPattern.Text.Trim(), this.ckbRecursive.Checked);
            DataTable dt = new DataTable();
            dt.Columns.Add("File");
            foreach (string name in names)
            {
                DataRow dr = dt.NewRow();
                dr[0] = name;
                dt.Rows.Add(dr);
            }
            dgvFiles.DataSource = dt;
            dgvFiles.Columns[0].Width = dgvFiles.Width;
            for (int i = 0; i )
            {
                dgvFiles.Rows[i].Selected = true;
            }

3. 在界面上筛选搜索结果,选择算法,点击“Update”按钮,做一些输入验证工作后更新文件,更新算法实例使用工厂获得

private void btnUpdate_Click(object sender, EventArgs e)
        {
            string error = ValidateInput();
            if (error == null)
            {
                IAlgorithm algorithm 
= Factory.CreateUpdateAlgorithm(this
.cmbArithmetic.SelectedItem.ToString());
                List<string> files = new List<string>();
                for (int i = 0; i )
                {
                    if(dgvFiles.Rows[i].Selected ==true)
                    {
                        files.Add(dgvFiles.Rows[i].Cells[0].Value.ToString());
                    }
                }
                algorithm.execute(files);
                this.panDisplay.Enabled = false;
                this.progressUpdate.Visible = true;
                this.progressUpdate.Value = 0;
                this.progressUpdate.Visible = false;
                this.panDisplay.Enabled = true;
                MessageBox.Show("Done!", "Update");
            }
            else
            {
                MessageBox.Show(error, "Error");
            }
        }

最后

这样一个简单的文件批量修改工具就完成了,点击这里下载源码,其实这个工具很简单,没任何高明之处,反而本着发布去写的小工具甚至有些粗糙,只是想借此说明几点

1. 设计模式与我们日常编程工作并不是遥不可及的,设计模式并不只是架构师的菜,只要认真发觉,我们每天使用的类库中都包含很多设计模式,有时候我们也在使用了,只是没发现

2. 设计模式的学习并不是看几本书、在网上看个大牛写的一系列教程就可以做到的,而在于我们对自己写的代码精益求精,发现违背设计原则的地方不断重构,结合理论指导,自然能够用出设计模式,一旦设计模式是自己慢慢演化去代码得来,相信大家就不在会问为什么要用这个模式、用了有什么好处、什么场景下用这个设计模式了。

纸上得来终觉浅,绝知此事要躬行。


推荐阅读
  • 使用Matlab创建动态GIF动画
    动态GIF图可以有效增强数据表达的直观性和吸引力。本文将详细介绍如何利用Matlab软件生成动态GIF图,涵盖基本代码实现与高级应用技巧。 ... [详细]
  • Hadoop MapReduce 实战案例:手机流量使用统计分析
    本文通过一个具体的Hadoop MapReduce案例,详细介绍了如何利用MapReduce框架来统计和分析手机用户的流量使用情况,包括上行和下行流量的计算以及总流量的汇总。 ... [详细]
  • 本文详细介绍如何在SSM(Spring + Spring MVC + MyBatis)框架中实现分页功能。包括分页的基本概念、数据准备、前端分页栏的设计与实现、后端分页逻辑的编写以及最终的测试步骤。 ... [详细]
  • STM32代码编写STM32端不需要写关于连接MQTT服务器的代码,连接的工作交给ESP8266来做,STM32只需要通过串口接收和发送数据,间接的与服务器交互。串口三配置串口一已 ... [详细]
  • Java连接MySQL数据库的方法及测试示例
    本文详细介绍了如何安装MySQL数据库,并通过Java编程语言实现与MySQL数据库的连接,包括环境搭建、数据库创建以及简单的查询操作。 ... [详细]
  • Excel技巧:单元格中显示公式而非结果的解决方法
    本文探讨了在Excel中如何通过简单的方法解决单元格显示公式而非计算结果的问题,包括使用快捷键和调整单元格格式两种方法。 ... [详细]
  • 探讨了在Ionic3项目中,使用`ionic serve`命令可以正常运行,但使用`ionic build --prod`命令进行生产构建时遇到错误的原因及解决方案。 ... [详细]
  • 本文探讨了如何使用Scrapy框架构建高效的数据采集系统,以及如何通过异步处理技术提升数据存储的效率。同时,文章还介绍了针对不同网站采用的不同采集策略。 ... [详细]
  • 一、使用Microsoft.Office.Interop.Excel.DLL需要安装Office代码如下:2publicstaticboolExportExcel(S ... [详细]
  • 本文介绍了如何使用 Python 的 Pyglet 库加载并显示图像。Pyglet 是一个用于开发图形用户界面应用的强大工具,特别适用于游戏和多媒体项目。 ... [详细]
  • 本文介绍了使用Python和C语言编写程序来计算一个给定数值的平方根的方法。通过迭代算法,我们能够精确地得到所需的结果。 ... [详细]
  • 本文提供了一个关于AC自动机(Aho-Corasick Algorithm)的详细解析与实现方法,特别针对P3796题目进行了深入探讨。文章不仅涵盖了AC自动机的基本概念,还重点讲解了如何通过构建失败指针(fail pointer)来提高字符串匹配效率。 ... [详细]
  • 笔记说明重学前端是程劭非(winter)【前手机淘宝前端负责人】在极客时间开的一个专栏,每天10分钟,重构你的前端知识体系& ... [详细]
  • 本文回顾了作者在求职阿里和腾讯实习生过程中,从最初的迷茫到最后成功获得Offer的心路历程。文中不仅分享了个人的面试经历,还提供了宝贵的面试准备建议和技巧。 ... [详细]
  • Java多线程售票案例分析
    本文通过一个售票系统的实例,深入探讨了Java中的多线程技术及其在资源共享和并发控制中的应用。售票过程涉及查询、收款、找零和出票等多个步骤,其中对总票数的管理尤为关键。 ... [详细]
author-avatar
丫头2502892725
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有