84669 person learning
152542 person learning
20005 person learning
5487 person learning
7821 person learning
359900 person learning
3350 person learning
180660 person learning
48569 person learning
18603 person learning
40936 person learning
1549 person learning
1183 person learning
32909 person learning
这种现象在所有的面向对象工程中都会遇到,在我们编码时,对一般的对象比如mvc的,我们可以把写好的类文件放到相应的model view controller包里面去。但是对于一些共用类就不那么好处理了,比如一些工具类,或者是共用对象,你对它一个类命名一个软件包吧好像有点浪费,但是他们之间又确实没啥关联。
model
view
controller
很常用的做法是全部放到一个类似util的包里,但是最近看到一篇文章说这样过于简单粗暴,而且其他人也不好理解这样的分层,不知道各位是怎么处理这个问题的。
util
走同样的路,发现不同的人生
对于这种问题,没有什么硬性规定,重要的是团队内部必须形成规范,且团队的每个成员必须遵守这个规范,这样的话,就会降低新加入成员的熟悉成本。
我们团队内部对于项目公用的一些工具类(类似StringUtils,CollectionUtils等),也会以Util打成包;对于一些模块内部的共用对象,如果是一些enum类,则会以enums打成包;如果是一些模块(例如module1等)内部层与层之间的对象,则会先以dto命名包,再将其放入用其模块名命名的子包内,对于一些模块之间共用的对象,放入common命名的子包,其他共用的类,也会类似的先按照业务功能命名包名,然后在包内,按照不同模块划分子包。
最后一点重要的还是形成并遵守规范。
理论上“对象”应该是由“状态”(数据)与“行为”(逻辑)组合而成,其中状态就是类成员变量,行为就是类成员方法。 楼主所说的工具方法,在大多静态语言中,本身就是非面向对象的东西,又如何以面向对象的方式组织?以Java中常用的Apache Commons Lang库为例,其中的大半类都是各种静态方法组成,例如StringUtils等——静态方法本身就是纯逻辑,与对象无关,也不会保持状态,可以说和平时我们写过程式语言的函数几乎一模一样,所以这类方法参考Apache Commons库或是java.util包写就好了,也是业内通用的做法。
但对于楼主提到的这类工具方法,这里我想补充一下,也算对上段“大多静态语言”这个定语的解释。如果抛开语言限制,仅看面向对象,那么多工具方法的存在其实大半是不合理的。
先看一下JDK自带的工具类java.util.Arrays类,随便挑一个方法,例如Arrays.sort(int[])对数字数组排序:
public static void sort(int[] a); public static void sort(int[] a, int fromIndex, int toIndex);
这个方法的调用为:
int[] xx = ... java.util.Arrays.sort(xx); java.util.Arrays.sort(xx, 1, 10);
以上静态方法的方式看似很合理——因为本来就是个排序逻辑嘛,但如果写成这样呢:
int[] xx = ... xx.sort(); xx.sort(1, 10);
是不是更加OO?我本来就要对数组排序,为何不让数组给自己排序?再看org.apache.commons.StringUtils类,随便找个方法例如:
public static boolean isAlpha(CharSequence cs);
调用时你更想写成下面哪样?
org.apache.commons.StringUtils.isAlpha(aString);
aString.isAlpha();
是不是让你想起了 "string".trim() "string".indexOf() 这些方法?如果你想,可以把StringUtils里的所有方法都变成String的成员方法。。。。。那为毛JDK不把这些东东变成成员方法,而是让它们以静态方法的方式存在于那些丑陋的纯行为类呢?这其实是由各种Java语言特性导致的,例如:
看看其他语言的情况: 1. JavaScript语言的string没有提供trim()方法,但我们可以扩展:
String.prototype.trim = function() { ... } "string ".trim();
2. Objective-C中对象扩展除了继承之外还可以使用Category的方式(而且Objective-C中对nil的设定灰常和谐)
@interface NSString (Cute) - (NSString *)beCute; @end ... [@"string" beCute];
因此,对于楼主的问题回答是:不是这些类无法归类,而是没有归好类或是语言特性使得很难去归类——只能归成Utils工具类了
最后,个人在这些年里见过的80%以上的 A.method(b) 其实都是可以变化成 b.method(),做到更加OO。其中最多最坑爹还最被广泛认同的一种写法就是:
userManager = ...UserManagerSingleton; userManager.save(user);
这里把明明是User的行为(save)拆分到独立的UserManager类里面搞得一个只有行为一个只有状态本就很奇怪了,还要把完全没有状态的UserManager实例化一个singleton出来,做一个OO假象给别人看。。。骗谁呢。。。还好Rod Johnson后来自己也承认Spring提倡的这种写法其实是在延续EJB时代的“事务脚本”,是anti-OO的东东。国内技术环境浮躁,不少人都是从SSH学起,还以为自己一直在写OO的代码,还以为自己懂OO。。。。
这就是我不提倡纯面向对象的原因之一, 很多时候可以作为一个函数的东东, 一定要被包装成一个类, 加上一个命名空间, 写成一个静态方法.
如果用一个比较好的语言系统, 应该首先语言标准库就提供很多重要的函数和类
其次是第三方库, 作为vendor
然后是本身有价值的东西, 可以有common, 或者内部开源成为一个第三方库, 规范接口.
我不提倡在一个公司的几个projects之间share common, 否则其他团队的修改会bug/crash你的产品, 不如将原来的common fork出来加以修改.
最后是和这个项目的直接相关的代码逻辑
团队沟通是成本最高的, 唯一的办法, 控制开发团队人数
关键还是在于你对代码的组织能力和对业务逻辑的建模能力。你的类名是否起得合适,能否描述这个类的真正业务职责。你的包名、类名应该反映你的业务逻辑,而不是简单的model,controll,view,这种名字只是反映的软件的架构,无法反映你真正的业务,我觉得是应该避免的。
我觉得是可以在controller和model间再思考的。
mvc也只是一种代码组织形式而已,但不要被mvc限定住,一个良好的层次可以不只是mvc。 如果你的业务场景里这三层是很简单,比如“数据库取下数据,controller里稍微加工下,view显示”,那么mvc就够了。 可如果controller下面的数据组织相当复杂,比如需要操作很多其他的系统,或是经过复杂的业务处理后才能得到最终的一份业务数据。那么controller和model之间可以做的文章还是很多的。
那这介于controller和model之间代码如何组织,可能是初步采用面向对象的思路后遇到的烦恼,但当真正理解面向对象对象的概念后其实情况还是可以很清楚的。觉得可以参考下一些关于“设计模式”的东西。
可以架设出很多个属于service(在本地对很多功能进行包装)的类,或者甚至把较独立的功能就封装成内部的api(http的server)。
面向对象本身就是坑,不是什么东西都一定要用类来包装的,比如函数,比如静态方法,比如全局对象?做java的有没有考虑过单例这么自然的东西为什么到java里就成了一个模式?
对于这种问题,没有什么硬性规定,重要的是团队内部必须形成规范,且团队的每个成员必须遵守这个规范,这样的话,就会降低新加入成员的熟悉成本。
我们团队内部对于项目公用的一些工具类(类似StringUtils,CollectionUtils等),也会以Util打成包;对于一些模块内部的共用对象,如果是一些enum类,则会以enums打成包;如果是一些模块(例如module1等)内部层与层之间的对象,则会先以dto命名包,再将其放入用其模块名命名的子包内,对于一些模块之间共用的对象,放入common命名的子包,其他共用的类,也会类似的先按照业务功能命名包名,然后在包内,按照不同模块划分子包。
最后一点重要的还是形成并遵守规范。
理论上“对象”应该是由“状态”(数据)与“行为”(逻辑)组合而成,其中状态就是类成员变量,行为就是类成员方法。
楼主所说的工具方法,在大多静态语言中,本身就是非面向对象的东西,又如何以面向对象的方式组织?以Java中常用的Apache Commons Lang库为例,其中的大半类都是各种静态方法组成,例如StringUtils等——静态方法本身就是纯逻辑,与对象无关,也不会保持状态,可以说和平时我们写过程式语言的函数几乎一模一样,所以这类方法参考Apache Commons库或是java.util包写就好了,也是业内通用的做法。
但对于楼主提到的这类工具方法,这里我想补充一下,也算对上段“大多静态语言”这个定语的解释。如果抛开语言限制,仅看面向对象,那么多工具方法的存在其实大半是不合理的。
先看一下JDK自带的工具类java.util.Arrays类,随便挑一个方法,例如Arrays.sort(int[])对数字数组排序:
这个方法的调用为:
以上静态方法的方式看似很合理——因为本来就是个排序逻辑嘛,但如果写成这样呢:
是不是更加OO?我本来就要对数组排序,为何不让数组给自己排序?再看org.apache.commons.StringUtils类,随便找个方法例如:
调用时你更想写成下面哪样?
是不是让你想起了 "string".trim() "string".indexOf() 这些方法?如果你想,可以把StringUtils里的所有方法都变成String的成员方法。。。。。那为毛JDK不把这些东东变成成员方法,而是让它们以静态方法的方式存在于那些丑陋的纯行为类呢?这其实是由各种Java语言特性导致的,例如:
看看其他语言的情况:
1. JavaScript语言的string没有提供trim()方法,但我们可以扩展:
2. Objective-C中对象扩展除了继承之外还可以使用Category的方式(而且Objective-C中对nil的设定灰常和谐)
因此,对于楼主的问题回答是:不是这些类无法归类,而是没有归好类或是语言特性使得很难去归类——只能归成Utils工具类了
最后,个人在这些年里见过的80%以上的 A.method(b) 其实都是可以变化成 b.method(),做到更加OO。其中最多最坑爹还最被广泛认同的一种写法就是:
这里把明明是User的行为(save)拆分到独立的UserManager类里面搞得一个只有行为一个只有状态本就很奇怪了,还要把完全没有状态的UserManager实例化一个singleton出来,做一个OO假象给别人看。。。骗谁呢。。。还好Rod Johnson后来自己也承认Spring提倡的这种写法其实是在延续EJB时代的“事务脚本”,是anti-OO的东东。国内技术环境浮躁,不少人都是从SSH学起,还以为自己一直在写OO的代码,还以为自己懂OO。。。。
这就是我不提倡纯面向对象的原因之一, 很多时候可以作为一个函数的东东, 一定要被包装成一个类, 加上一个命名空间, 写成一个静态方法.
如果用一个比较好的语言系统, 应该首先语言标准库就提供很多重要的函数和类
其次是第三方库, 作为vendor
然后是本身有价值的东西, 可以有common, 或者内部开源成为一个第三方库, 规范接口.
我不提倡在一个公司的几个projects之间share common, 否则其他团队的修改会bug/crash你的产品, 不如将原来的common fork出来加以修改.
最后是和这个项目的直接相关的代码逻辑
团队沟通是成本最高的, 唯一的办法, 控制开发团队人数
关键还是在于你对代码的组织能力和对业务逻辑的建模能力。你的类名是否起得合适,能否描述这个类的真正业务职责。你的包名、类名应该反映你的业务逻辑,而不是简单的model,controll,view,这种名字只是反映的软件的架构,无法反映你真正的业务,我觉得是应该避免的。
我觉得是可以在controller和model间再思考的。
mvc也只是一种代码组织形式而已,但不要被mvc限定住,一个良好的层次可以不只是mvc。
如果你的业务场景里这三层是很简单,比如“数据库取下数据,controller里稍微加工下,view显示”,那么mvc就够了。
可如果controller下面的数据组织相当复杂,比如需要操作很多其他的系统,或是经过复杂的业务处理后才能得到最终的一份业务数据。那么controller和model之间可以做的文章还是很多的。
那这介于controller和model之间代码如何组织,可能是初步采用面向对象的思路后遇到的烦恼,但当真正理解面向对象对象的概念后其实情况还是可以很清楚的。觉得可以参考下一些关于“设计模式”的东西。
可以架设出很多个属于service(在本地对很多功能进行包装)的类,或者甚至把较独立的功能就封装成内部的api(http的server)。
面向对象本身就是坑,不是什么东西都一定要用类来包装的,比如函数,比如静态方法,比如全局对象?做java的有没有考虑过单例这么自然的东西为什么到java里就成了一个模式?