如何正确划分我的代码? [英] How Do I Divide My Code Appropriately?

查看:137
本文介绍了如何正确划分我的代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,



我现在正在尝试学习一些基础知识,特别是如何将我的代码划分为单独的类和文件以使其更清晰。



关于代码:

这个片段将成为备份解决方案的一部分,我想复制数据库文件,获取备份前后文件的信息并发送了相关信息。我知道,有解决方案,但我想自己做(并顺便学习)。

特别是这个片段可以/应该告诉我,如果我的新文件有备份文件夹。



关于目标:

我的主要目标是:学习如何获得通用课程这让我的代码更加清晰(直到现在,我基本上只有一个类和很多方法,因为我之前只编写过脚本)

所以,对于我的备份项目,我希望有文件操作的一个类,如复制,删除,移动等,一个用于FileInfos,如路径,或一个用于电子邮件。

最后我希望有类(或我的项目中的* .cs文件),比如

FileCopy.cs

FileMove.cs

FileDel.cs

FileInfo.cs

CompareDirs.cs

DirInfo.cs

SendEmail.cs

(我可能不需要所有这些,但我希望我能说清楚)



下面是一些代码我已经分成两个班。它有效,但我有一些问题:



1.我很感激您对如何使这个特定代码更好或更好的建议。

2.我如何概括它,意思是:我如何从调用者传递所需的DirectoryInfos(此处:diSub.FullName和diSub.GetFiles()。Length)?

3.如何动态扩展列表,例如,如果我需要一个包含三个或四个字符串的List?





提前许多

Axel



课程(计算子目录中的文件)

Hi all,

I trying to learn some basics right now, especially how to divide my code into separate classes and files to make it clearer.

About the code:
This fragment will be part of a backup solution where i want to copy database files, get infos about files before and after backup and sent information about it. I know, there are solutions for that, but i'd like to do (and learn by the way) it myself.
Particularly this fragment could/should tell me, if there are new files in my backup folders.

About the goal:
My main goal here is: learn how to get generalized classes which make my code more clear (Till now, i just had basically one class and a lot of methods, because i merely scripted before)
So, for my backup-Project, I'd like to have one class for Fileoperations like copy, delete, move and so on, one for FileInfos like path or , one for email.
In the end i would like to have classes(or *.cs files in my project) like
FileCopy.cs
FileMove.cs
FileDel.cs
FileInfo.cs
CompareDirs.cs
DirInfo.cs
SendEmail.cs
(I may not need all of them, but I hope i made myself clear)

Below is some code which i already divided into two classes. It's working, but i got some questions:

1. I would appreciate your suggestions on how to make this particular code better or right.
2. How would i generalize it, meaning: How could i pass the desired DirectoryInfos (here: diSub.FullName and diSub.GetFiles().Length) from the caller?
3. How could i expand the list dynamically, for example if i need a List with three or four strings?


Thx a lot in advance
Axel

The class (counting files in subdirs)

class MyFileSearch
    {
        // List for Dir Values
        List<Tuple<string, string>> m_myDirList = new List<Tuple<string,string>>();
        
        // get List from the outside
        public List<Tuple<string, string>> myDirList
        {
            get
            {
                return m_myDirList;
            }
        }
        
        public void TraverseFileSystem(DirectoryInfo di)
        {
            try
            {
                // for all files in actual directory
                foreach (FileInfo fi in di.GetFiles())
                {
                    //do somthing
                }

                // for all subdirs in actual directory
                foreach (DirectoryInfo diSub in di.GetDirectories())
                {
                    // fill list
                    m_myDirList.Add(new Tuple<string, string>(diSub.FullName,diSub.GetFiles().Length.ToString()));
                    
                    // Serach subdirs of actual directory
                    TraverseFileSystem(diSub);
                }
            }
            catch (Exception e)
            {
                // Error
                MessageBox.Show("error: " + e.ToString());
            }
        }
    }





我在这里打电话给MyFileSearch





Here i call MyFileSearch

private class MyMainClass
    {
    //...
private void MyFileCount()
        {
            // Create Instances 
            StringBuilder sb = new StringBuilder();
            MyFileSearch myfs = new MyFileSearch();
            DirectoryInfo dis = new DirectoryInfo("C:\\tmp");
            
            // call Method and sort List
            myfs.TraverseFileSystem(dis);
            myfs.myDirList.Sort();

            // output Listresults
            for (int j = 0; j < myfs.myDirList.Count; j++)
            {
                if (myfs.myDirList[j].Item1 != "")
                {
                    sb.AppendLine("Dir: " + myfs.myDirList[j].Item1 + " Files in Dir: " + myfs.myDirList[j].Item2);
                }
            }
            MessageBox.Show(sb.ToString());
        }
        //...
}

推荐答案

说实话,这可能不比你分开之前的版本更清晰 - 你所做的就是移动在不考虑价值观的情况下将价值观纳入一个类。



而不是想我有这个代码,我该如何分解?,我会建议您考虑一下您要处理的数据并研究如何组织它。



所以我首先创建一个类来保存我的文件信息把它放入一个匿名元组:

To be honest, that probably isn't a lot clearer than the version before you "divided it up" - all you have done is move values into a class without thinking about what the values are there for.

Instead of thinking "I have this code, how do I break it up?", I would suggest that you think about the data you are going to process and work on how to organise that.

So I would start by creating a class to hold my file information instead of puting it into an anonymous tuple:
public class Folder
   {
   public string Path { get; set; }
   private List<string> _Files = new List<string>();
   public List<string> Files { get { return _Files; }}
   ...
   }

现在您的外部方法可以按名称引用文件夹及其内容,这更好地反映了文件夹的组织方式。 (或者,如果你知道继承是什么,我会直接从字符串列表派生我的Folder类。)

然后我会设置一个文件夹列表来保存它们。 />


看看我的意思?



这些是我的想法,也许你可以开导我:

如果我有这个类Folder,据我所知,这个类代表一个对象(我用new-Operator初始化),在这种情况下我的对象是一个文件夹对吧?

现在我的代表我的对象的类应该有属性和方法。一个属性就是大小,一个方法是复制文件夹。对吧?




是 - 但是......你需要一个单独的操作来加载文件吗?或者在Folder Constructor中自动执行此操作会更好吗?也许提供刷新方法?这样,Size属性总是有信息可以使用! :笑:



所以你的构造函数有一个参数 - 文件夹的路径 - 它会自动加载它的文件。



不要去寻找方法添加 - 你需要的那些将是非常明显的,除非它向现有File.Copy和File添加内容,否则添加Copy或Move方法没有意义。移动方法。



基本上,将一个类视为数据的块加上你应用的操作 - 并让它继续工作而不是用较旧的,程序性的方式思考。在OOP环境中,数据控制着它自己的操作 - 它们可以从类外部启动,但实现取决于类本身。



想想一辆车class:它会有一个StartEngine方法,知道引擎是汽油还是柴油,并应用正确的启动程序,而外界不必知道(或关心)它是什么类型。

Now your external methods can refer to the folder and it's contents by name, which better reflects how folders are organised. (Or, if you know what inheritance is yet, I'd derive my Folder class directly from a List of strings).
Then I'd set up a list of Folders to hold them.

See what I mean?

"Those were my thoughts, maybe you can enlighten me:
If I have this class "Folder", as far as I understand it, this class represents an object (which I initialize with the "new"-Operator), in this case my object is a folder. Right?
Now my class representing my object should have properties and methods. A property would be for example the size, a method would be to copy the folder. Right?"


Yes - but...do you need a separate operation to "load" the files? Or would it be better to automatically do that in the Folder Constructor? And perhaps provide a "Refresh" method? That way, the Size property always has info to work on! :laugh:

So your constructor has a parameter - the path to the folder - and it automatically loads it's files.

Don't go "looking for methods" to add - the ones you need will be pretty obvious, and there is no point in adding a Copy or Move method unless it adds something to the existing File.Copy and File.Move methods.

Basically, think of a class as a "chunk" of data plus the operations which you apply to it - and let it get on with the work, instead of thinking in the older, procedural way. In an OOPs environment, the data controls it's own operations - they can be initiated from outside the class but the implementation is up to the class itself.

Think of a Car class: it would have a "StartEngine" method that "knows" if the engine is petrol or diesel and applies the correct starting procedure without the outside world having to know (or care) what type it is.

你的例子太简单了,不能认真讨论代码和模块化的分离,但我会冒险给出一些建议。它应该被认为是一些思考的食物,而不是一套规则。



所以,首先,未来的单位,无论它们是什么,都应该是虽然是2D空间中的东西。为何选择2D?因为添加更多维度很难保持在开发人员的想象中:我们的愿景本质上是2D,任何更简单的都是太原始的。所以,你在心理上垂直和水平地安排你的单位。



垂直分色应该是分层的:你在底层放置最抽象,最基本和应用 - 不可知的设施,因此,将是最普遍的。换句话说,如果某些功能不太可能改变(但可以扩展),更适合于当前应用中更广泛的可能未知变化的更广泛的应用,它们更有可能在底部实现。应用程序本身位于顶层;如果你有一些插件机制,插件就属于最顶层。在一些大型系统中,我明确地命名了层,从下到上,不可知(语义不可知)或通用,然后是语义,然后是应用程序和插件。同样,这不是一个规则,只是一个想法;而且你不应该让它比你的整个解决方案要求更复杂。图层的主要规则:每个图层都可以使用任何底层,但不能使用任何顶层。换句话说,任何层都应该与上层内容保持完全无关(但作为开发人员,您应该完全了解下层的目的及上层的使用)。而依赖性原则规则。



水平分离它与主题的分离。示例是:网络,数据,文件系统,图形,UI等。请注意,某些水平单位可以在一个图层上表示,但它们可以位于一个或多个图层中。例如,一些不可知的数据管理机制可以在基础层上,但是,一些语义数据模式可以位于其上方的语义层上;它将使用通用层的数据单元。再一次,这只是一个例子。



我不解释这些单位应该是什么。这实际上取决于您的解决方案的规模。例如,图层应该是由整个单独项目组表示的比例,每个项目代表一个水平的主题;因此,这些项目组也应放在不同的目录,物理,解决方案文件夹或两者中。同时,在更小的解决方案中,整个层可以只占用一个代码文件。你可以使用它们之间的所有比例。在更大的范围内,一个层可以占用整个主机并代表一个单独的层。



要理解的一件重要事情:使用.NET,类型(类,结构) )比文件更稳定,文件比程序集更稳定。这意味着:不要过多地划伤你的脑袋来决定装配的内容。程序集是.NET中最基本的概念,然而,将一些代码从一个程序集移动到另一个程序集太容易了。从开发的角度来看,程序集之间的界限几乎是不可见的(您只需要使用公共和受保护的访问修饰符)。您可以轻松地从单一解决方案开始,并在它变得更复杂时将其拆分。 由于质量或正确性,您的决定不好,如果将来更容易改变,它们真的很好。换句话说:不要害怕犯错误,害怕做出太坚定的决定,防止纠正你的错误。



一般来说,最多模块化中的重要考虑因素应该是:思考你的决策是否稳定。主要的是要明白你以后应该能够改变一切;所以你可以做出中间或临时的决定。尝试将不确定与确定分开。



更多细节:UI扮演特殊角色,应尽可能隔离。为什么?我认为这是因为一个重要的社会/文化因素:UI架构的出现和消失太快了。让我们说,这是一个实用计算领域和技术领域,它是最不稳定的领域。有许多方法致力于将UI与解决方案的其他方面隔离开来。请参阅:

http://en.wikipedia .org / wiki / Presentation%E2%80%93abstraction%E2%80%93control [ ^ ],

http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller [ ^ ],

http://en.wikipedia.org/wiki/Hierarchical_model%E2%80 %93view%E2%80%93controller [ ^ ],

http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93adapter [ ^ ],

http://en.wikipedia.org/wiki/Observer_pattern [ ^ ],

http:// en .wikipedia.org / wiki / Model_View_ViewModel [ ^ ] 。



参见:

http: //en.wikipedia.org/wiki/Modular_programming [ ^ ],

http://en.wikipedia.org/wiki/Multi tier_architecture [ ^ ],

http://en.wikipedia.org/wiki/Modularity#Modularity_in_technology_and_management [ ^ ],

http://en.wikipedia.org/wiki/Modular_design [ ^ ]。



-SA
You example is too simple to discuss the separation of code and modularization seriously, but I'll take a risk to give some advice. It should be considered as some food for thought, not a set of rules.

So, first of all, the set of prospective units, whatever they are, should be though as something in 2D space. Why 2D? Because adding more dimensions would be hard to keep in the developers imagination: our vision is 2D in its nature, and anything simpler would be too primitive. So, you mentally arrange your units "vertically" and "horizontally".

Vertical separations should be layered: you put on the bottom layer the most abstract, fundamental and application-agnostic facilities, and, hence, the will be the most universal. In other words, if some features are less likely to change (but can be extended), are more suitable for wider range of applications of wider range of possible yet unknown changes of your current application, the more likely they should be implemented in the bottom. The application itself is on the top layer; and if you have some plug-in mechanism, the plug-ins belong on the very top. In some big systems, I explicitly named the layers, bottom to top, "Agnostic" (semantic-agnostic) or "Universal", then "Semantic", then "Application" and "Plug-in". Again, this is not a rule, just an idea; and you should not make it more complex than your whole solution requires. The main rule of the layers: each layer can use any of the bottom layers, but never any of the top layers. In other words, any layer should be kept totally agnostic to the content of upper layer (but you, as a developer, should be totally aware of the purpose of down layer and its use by upper layers). And that dependency principle is the rule.

Horizontal separation it the separation by the "topic". Examples are: "network", "data", "file system", "graphics", "UI", and so on. Note that some horizontal units can be represented on one layer, but they could be in one or more layers. For example, some agnostic data management mechanism could be on the fundamental layer, but, say, some semantic data schema can be on the semantic layer above it; and it will use data units of the universal layer. Again, this is just an example.

I don't explain what those units should be. It really depends on the scale of your solution. For example, the layer should be of the scale represented by the whole group of the separate projects, each project representing a horizontal "topic"; so those groups of projects should be also placed in different directories, physical, solution folders, or both. At the same time, in much smaller solution, the whole layer could occupy just one code file. And you can use all the scales in between. In even bigger scale, a layer could occupy the whole host machine and represent a separate tier.

One important thing to understand: with .NET, types (classes, structures) turn out much more stable than files, and files more stable than assemblies. It means: don't scratch your head too much to decide what goes to what assembly. Assembly is the most fundamental concept in .NET, and yet, it's way too easy to move some code from one assembly to another. From the development point of view, the boundaries between assemblies are almost invisible (you only need to use public and protected access modifiers). You can easily start from a monolithic solution and split it as it become more complex. Your decision not good because of their quality or correctness, they are really good if they are easier to change in future. In other words: don't be afraid of making mistakes, be afraid of making too firm decision preventing fixing your mistakes.

Very generally, the most important consideration in you modularization should be: think how stable your decisions are. Main thing is understanding that you should be able to change everything later; so you can make intermediate or temporary decisions. Try to separate less certain from more certain.

Some more detail: UI plays special role and should be isolated as much as possible. Why? I think this is because of one important social/cultural factor: UI architectures emerge and disappear too quickly. Let's say, this is a field of practical computing and the technosphere which is the least stabilized one. There is a good number of approaches dedicated to isolation of UI from other aspects of the solution. Please see:
http://en.wikipedia.org/wiki/Presentation%E2%80%93abstraction%E2%80%93control[^],
http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller[^],
http://en.wikipedia.org/wiki/Hierarchical_model%E2%80%93view%E2%80%93controller[^],
http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93adapter[^],
http://en.wikipedia.org/wiki/Observer_pattern[^],
http://en.wikipedia.org/wiki/Model_View_ViewModel[^].

See also:
http://en.wikipedia.org/wiki/Modular_programming[^],
http://en.wikipedia.org/wiki/Multitier_architecture[^],
http://en.wikipedia.org/wiki/Modularity#Modularity_in_technology_and_management[^],
http://en.wikipedia.org/wiki/Modular_design[^].

—SA

由于我的同事兼导师OriginalGriff已经在解决方案领域崭露头角,太阳的光芒照耀着他辉煌的光亮盔甲;我将加入。



引起我的注意的第一件事就是你宣称'MyFileCount是私有的,所以它永远不会在'MyMainClass的实例中可见,并且,你打电话给方法:



myfs.TraverseFileSystem(dis);



在'MyFileCount中,但'MyFileSearch中的TraverseFileSystem方法被声明为'私有。



因此,此方法在'MyFileSearch外部不可见。这是两个不会编译的惩罚标志:)



这可能不重要,但我也注意到这段代码将忽略根目录下的文件正在搜索的目标文件夹......但是你在代码中确实有一个注释。



考虑到你对良好组织的广泛关注,我认为是你需要构建的一些关键问题:



1.我写这段​​代码的意图是什么:目标是什么,底线?



2.我是针对特定情况编写的一次性修复或解决方案,永远不需要再次更改,永远不想重复使用代码并适应其他情况?当然,这个修辞问题的反面是要问:我是否想要努力创建一个可重用的工具,通过参数或多个构造函数等,可以用来在将来执行类似的任务? br />


这个问题的另一个必然结果是,imho:还有其他人会使用/重新使用这段代码吗?我是否在有预期的团队工作,以及正式或非正式的代码风格和/或组织风格指南。



3.我是否需要注释这段代码,以便其他人可以快速了解它是如何工作的?



4.我是否以某种方式使用了Class,Field,Property和Method,Names使每个结构的目的和用途清楚?



根据你如何回答这些问题,我认为组织的不同标准出现了。



我承认可能是偏见:当我看到没有构造函数执行单个任务的类时,我倾向于立即将重新分解为某种静态方法,也许是一个静态实用程序库,其他方法可以处理类似的对象。



另一个可以采用的观点是否静态,要注意.NET本身有很多可以实例化的对象的例子d(使用'new'创建)具有静态方法:例如'String。
Since my colleague and mentor, OriginalGriff, has sallied forth on the Field of Solutions, with the brilliant rays of the Sun reflecting off his resplendent burnished armor; I will join in.

The first thing that "catches my eye" is you declared 'MyFileCount private, so it will never be visible in an instance of 'MyMainClass, and, you call the method:

myfs.TraverseFileSystem(dis);

In 'MyFileCount, but the method 'TraverseFileSystem in 'MyFileSearch is declared 'private.

So, this method will not be visible outside 'MyFileSearch. That's two "won't compile" penalty flags :)

This may not be important, but I also notice that this code will ignore files at the root level of the target folder being searched ... but you do have a note there, in the code, about that.

Looking toward your wider concern for good organization, I think there are some critical questions you need to frame:

1. What is my intent in writing this code: what is the goal, the "bottom line" ?

2. Am I writing as a one-off fix, or solution, for a specific case, and will never need to change it again, will never want to re-use the code and adapt it for other situations ? Of course, the reverse of that rhetorical question is to ask: do I want to make the effort to create a reusable tool that, through parameters, or multiple constructors, etc., can be used to carry out similar tasks in the future ?

Another corollary of this question is, imho: are other people going to be using/re-using this code ? Do I work in a Team where there are expectations, and formal, or informal, guidelines for code style, and/or organizational style.

3. Do I need to annotate this code so other people can quickly understand how it works ?

4. Did I make use of Class, Field, Property, and Method, Names in a way that makes the purpose and use of each of those constructs clear ?

Depending on how you answer those questions, then I think different criteria for "organization" ... emerge.

I admit to what may be a "bias:" when I see Classes with no constructors that perform a single task, I tend to immediately think of re-factoring as some kind of static Method, perhaps one to be in a static utility library with other Methods that work with similar objects.

Another point-of-view one can take on whether to "go static," is to note that .NET itself has many examples where Objects that can be instantiated (created with 'new) have static methods: for example 'String.


这篇关于如何正确划分我的代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆