方法多少个参数才算多!

震我一下巧克力 2011-07-12 03:42:00
加精
小弟有这样一个方法,按页大小和页索引查询产品,如下。
        /// <summary>
/// 获取产品
/// </summary>
/// <param name="manufacturerID">厂商ID,为null时不做查询条件。</param>
/// <param name="categoryID">类别ID,为null时不做查询条件。</param>
/// <param name="typeID">类型ID,为null时不做查询条件。</param>
/// <param name="name">产品名称,模糊匹配。</param>
/// <param name="description">描述,模糊匹配。</param>
/// <param name="pageSize">页大小</param>
/// <param name="pageIndex">页索引</param>
/// <returns></returns>
public DataTable GetProduct(int? manufacturerID, int? categoryID, int? typeID, string name, string description, int pageSize, int pageIndex)
{
......
}

可以看到小弟这个方法参数比较多,有7个,这时有人就说了:“这么多参数,应该封装成一个对象传递!”要写成下面这个样子。
    public class QueryProduct
{
private int? manufacturerID;

/// <summary>
/// 厂商ID,为null时不做查询条件。
/// </summary>
public int? ManufacturerID
{
get { return manufacturerID; }
set { manufacturerID = value; }
}

private int? categoryID;

/// <summary>
/// 类别ID,为null时不做查询条件。
/// </summary>
public int? CategoryID
{
get { return categoryID; }
set { categoryID = value; }
}

private int? typeID;

/// <summary>
/// 类型ID,为null时不做查询条件。
/// </summary>
public int? TypeID
{
get { return typeID; }
set { typeID = value; }
}

private string name;

/// <summary>
/// 产品名称,模糊匹配。
/// </summary>
public string Name
{
get { return name; }
set { name = value; }
}

private string description;

/// <summary>
/// 描述,模糊匹配。
/// </summary>
public string Description
{
get { return description; }
set { description = value; }
}

private int pageSize;

/// <summary>
/// 页大小
/// </summary>
public int PageSize
{
get { return pageSize; }
set { pageSize = value; }
}

private int pageIndex;

/// <summary>
/// 页索引
/// </summary>
public int PageIndex
{
get { return pageIndex; }
set { pageIndex = value; }
}
}


    /// <summary>
/// 获取产品
/// </summary>
/// <param name="query">查询条件</param>
/// <returns></returns>
public DataTable GetProduct(QueryProduct query)
{
......
}

小弟心里就想了 ,这才几个参数,连10个都不到,封装成一个对象有必要吗?

下面是各自对问题的看法

应该封装成对象:
1.不封装成对象,代码看起来很乱。
2.可维护性强,以后这个方法如果需要加查询参数,只需要在QueryProduct类中增加一个属性即可,方法不用改。
3.方法的参数越少越好,能少一个,绝不多一个。
4.方法的参数超过3个就要封装成对象。

应该直接传递参数:
1.直接将查询条件写在方法参数上,可读性强,便于后来人维护。
2.封装成对象,项目中就需要增加一个对象,对象越多,越不利于维护,10个以内的参数,如果没有特殊原因,不需要封装成对象。
3.这里的参数每一个都有业务意义,并不是要持久化到数据库的实体属性,在数量不多的时候,不应该封装成对象。

下面是小弟对“应该封装成对象”一派3个理由的回复
1.不封装成对象,代码看起来很乱。
一点都不乱,封装成对象反倒增加了阅读成本。
2.可维护性强,以后这个方法如果需要加查询参数,只需要在QueryProduct类中增加一个属性即可,方法不用改。
可维护性绝对没有增强,反倒因为项目中多了一堆查询条件对象,增加了阅读成本,降低了维护性。当增加查询条件时,改了查询对象的定义,方法的参数就变了,方法也100%的变了,只是方法的代码没改,但方法的定义已经改了,这完全没有优势。都是改代码,都是改方法的参数,都改变了方法的定义。
3.方法的参数越少越好,能少一个,绝不多一个。
这里没有一个参数是多余的,少任何一个参数都不能满足需求,方法的参数越少越好是毋庸置疑的,但绝不是用这种坑爹的方式减少参数。
4.方法的参数超过3个就要封装成对象。
是否要将参数封装成对象,不能只看参数的数量,还要看它的业务意义,作为数据载体的实体类,即使只有两个属性,也要用对象传递。但像这种,不需要持久化,而且每个参数都有各自的业务意义,没有特殊原因,就应该写在方法的参数列表里。

关于这个问题,小弟希望看看大家是怎么对待的,希望大家能在回复时除了表述自己的观点,同时告知在项目中会采取哪种方式。
...全文
8275 489 打赏 收藏 转发到动态 举报
写回复
用AI写文章
489 条回复
切换为时间正序
请发表友善的回复…
发表回复
Felix_Ding 2012-07-10
  • 打赏
  • 举报
回复
楼主的问题是考虑如何“按页大小和页索引查询产品”,我有这么个思路不知是否合适:
楼主纠结的是查询条件很多,讲每个条件作为一个参数传进函数里很蛋疼(无论是封装还是不封装)。
那么就把这些查询条件写入一个文件中,比如用XML之类的,那么这些查询条件相当于配置文件,用来配置此次查询要以什么条件值来查。查询的函数,也只需要一个参数了,就是配置文件路径,函数里面再用XML解析器去分别从文件中获取查询条件。
jedochn2 2012-05-04
  • 打赏
  • 举报
回复
好多的参数,我们也这么干
  • 打赏
  • 举报
回复
推荐看看code complete,一般7个左右吧,封装不封装不是看参数个数的。
siemens_chang 2011-11-24
  • 打赏
  • 举报
回复
具体情况,50多个字段一个个封装也很慢,但要是方法很多的话就封装起来,这样利用率高点
maj0123 2011-11-23
  • 打赏
  • 举报
回复
[Quote=引用 494 楼 maj0123 的回复:]
像LZ所说的函数中存在多个参数的现象也是比较常见的问题。在一些大点的项目中,我们经常碰到4
~50甚至更多的参数。把所有的参数封装到类、结构体也是可以的,这样一来在函数体中取值比较方便。但是在传值的时候,就必须格外小心,注意不能漏传参数。如果参数都封装到数组,列表中,取值的时候就必须依次取出,还必须注意类型转换。如果直接传值,虽然参数列表比较长,但也有其好处,从参数类型到参数名都有明确定义,所以……
[/Quote]

如果采用直接传递多个参数,在需求发生变化时,重载该函数就行了。
maj0123 2011-11-23
  • 打赏
  • 举报
回复
像LZ所说的函数中存在多个参数的现象也是比较常见的问题。在一些大点的项目中,我们经常碰到4
~50甚至更多的参数。把所有的参数封装到类、结构体也是可以的,这样一来在函数体中取值比较方便。但是在传值的时候,就必须格外小心,注意不能漏传参数。如果参数都封装到数组,列表中,取值的时候就必须依次取出,还必须注意类型转换。如果直接传值,虽然参数列表比较长,但也有其好处,从参数类型到参数名都有明确定义,所以在调用函数传值时,不容易发生错误。
lxblessyou 2011-10-13
  • 打赏
  • 举报
回复
没有规定啊 随便
sxiangs 2011-10-13
  • 打赏
  • 举报
回复
[Quote=引用 117 楼 wang153723482 的回复:]
函数不过屏
+1

引用 6 楼 ch_fb 的回复:

五个我就考虑,七个就封,十个就没商量了。
否则我函数不过屏的原则将难以保证。
[/Quote]
好 喜欢
Grubby_F 2011-09-22
  • 打赏
  • 举报
回复
学习了。~~
rjw_999 2011-08-05
  • 打赏
  • 举报
回复
我觉得就你这个问题,封不封都行,还是看你以后会不会修改
  • 打赏
  • 举报
回复
结贴了,分不多,小弟给了最前面的和最后面的,不公正的地方还请大家多多包涵。
每个人的回复小弟都仔细看过,看些大家。
个人感觉,很多说一定要封装的人,都没有仔细思考过这个问题。
jacksonhzs 2011-07-24
  • 打赏
  • 举报
回复
每天发帖可得10分。
cdefg198 2011-07-23
  • 打赏
  • 举报
回复
天天修改,老板的想法天天变化,不仅方法要变,连数据库都要变,搞得才痛苦哦。各个参数之间没有联系,就没必要封装。
fjwhq 2011-07-23
  • 打赏
  • 举报
回复
学习了
ITCore168 2011-07-23
  • 打赏
  • 举报
回复
自己看着办.......
yizhili 2011-07-22
  • 打赏
  • 举报
回复
这个例子和前面举出的例子和楼主的情况其实都不太一样。
楼主的例子前5个参数其实有共通点,属于“同类”
5个参数都是“互不相关”的查询条件
5个参数都是可选的
而几个例子中都不具备这样的特点。

你说的没错,要不要封装不是以参数个数为准,而是看具体函数有没有这个需要。但具体到楼主给出的函数,需要不需要封装呢?我认为需要。

[Quote=引用 456 楼 sp1234 的回复:]

其实我们随随便便就能找到追问的实例。比如看看BitMap类,它的实例化方法C# code
public Bitmap(Image original);
public Bitmap(Stream stream);
public Bitmap(string filename);
public Bitmap(Image original, Size newSize);……
[/Quote]
yizhili 2011-07-22
  • 打赏
  • 举报
回复
不是说写得时候有多难,而是写完以后看得时候有多难

Query(1,2,3);

谁能一眼看出 1, 2, 3 是什么?

Query( new Condition() { Id = 1, Category = 2, Price = 3 } );

每一个参数的意义都很明显。
如果不支持 C# 3.0,也可以通过适当的方法写成:

Query( new Conditon().Id(1).Category(2).Price(3) );


[Quote=引用 359 楼 fkago 的回复:]
如果调用一个方法时参数列表有一长串,你能看出来每个值是什么含义吗?(标准答案:很难)
有多难?难到非要建一个对象?
你用对象的时候能通过“.”找出属性,是谁帮你做了事情,是Visual Studio让你用起来这么方便,当你在调用方法时Visual Studio同样会给出提示,显示出方法参数的参数名和每个参数的注释,这么几个参数,不至于眼花吧。
还记得多少次写成这样吗?product.manufacturerID = categoryID
[/Quote]
yizhili 2011-07-22
  • 打赏
  • 举报
回复
看了楼主的函数签名,第一个想法是 LINQ 是王道
不过我对 LINQ to SQL 不熟,不会用它写分页,但还有个折中的方法
事实上将参数封装成对象不一定要封装所有参数,比如楼主的函数就可以写成:

public DataTable GetProductsByPage(QueryCondition condition, int pageSize, int pageIndex)
{
......
}

前面几个参数作用一致,关系比较紧密,而且有多个可选参数,可以封装在一起,在其他查询函数中或许还可重用;而 pageSize 和 pageIndex 与之没有多少关联,可以单独列出。
而其他人看到 QueryCondition 虽然不知道具体可以有哪些查询条件,也知道这是查询条件,而且这个函数可以对查询結果进行分页。

GetProductsByPage(new QueryCondition() { Name = "abc", Discription = "blabla" }, 10, 0);

也比

GetProduct(null, null, null, "abc", "blabla", 10, 0);

更好懂一些。

当然楼主后来也说到可以为不同参数建立不同函数,但是5个参数可以有32种组合,虽然不可能每一种都用到,但要增加业务逻辑也很难说。而且如果要增加一个参数,那基本上每个调用的地方都要改一遍。

更进一步,QueryCondition 可以变成 Query 类,用法变成:

new Query() { Id = 123 }.Get();
new Query() { Name = "abc" }.GetByPage(10, 0);

或者可读性更强的

new Query().IdIs( 123 ).Get();
new Query().NameLike( "abc" ).GetByPage(10, 0);

甚至于条件可以不限定于相等和相似比较

new Query().PriceLargeThan( 10 ).GetByPage(10, 0);

odp_denden 2011-07-22
  • 打赏
  • 举报
回复
路过,学习学习
xuxinmmy 2011-07-22
  • 打赏
  • 举报
回复
拉这么长个帖子才发现,楼主根本无意学习改进自己的程序设计思想,只是发个帖子来吵架玩的~~~~
加载更多回复(469)

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧