解决方法参数过多导致的编程问题
解决方法参数过多导致的编程问题
解决方法参数过多导致的编程问题
00 问题
在编码中, 遇到了这种场景. 一个总的方法, 有三个参数, 这个方法内部又使用了另外三个方法, 这些方法使用的参数是总的方法中的参数, 类似下方的伪代码.
1
2
3
4
5
6
void FuncMain(para a, para b, para c)
{
FuncA(a);
FuncB(b);
FuncC(c);
}
此时, 因为功能的扩展, 变成了下面这样的格式
1
2
3
4
5
6
void FuncMain(para a, para b, para c, para d, para e, para f)
{
FuncA(a, d);
FuncB(b, e);
FuncC(c, f);
}
此时, 你需要去改变所有方法的参数. 如果这些方法是跨文件的, 那么改动起来会非常麻烦.
01 解决方案
通常来说, 最常用的解决方案就是将这些参数写入一个结构体或者类中. 使用引入'参数对象'(Parameter Object)来整合膨胀的参数.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class SubShaderOptions
{
public string RenderType { get; set; }
public string RenderQueue { get; set; }
public bool ComplexLit { get; set; }
public PassSubTargetParams PassParams { get; set; }
public HashSet<ToggleDefinition> KeywordToggles { get; set; }
public GIMode GiMode { get; set; }
// 以后要加新控制项,只往这里扩展就行
}
// 调用处就只剩两个参数:
public static SubShaderDescriptor ExtendedLitGLESSubShader(
UniversalTarget target,
WorkflowMode workflowMode,
SubShaderOptions opts)
{
// 直接用 opts.RenderType、opts.GiMode ……
}
在这个基础上, 还可以引入Builder(生成器模式)来让参数的构成更直观. 伪代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 1. 定义 Builder 接口
interface ISubShaderBuilder
{
ISubShaderBuilder WithRenderType(string type);
ISubShaderBuilder WithRenderQueue(string queue);
ISubShaderBuilder UseComplexLit(bool complexLit);
ISubShaderBuilder WithPassParams(PassSubTargetParams p);
ISubShaderBuilder WithKeywords(HashSet<ToggleDefinition> keywords);
ISubShaderBuilder WithGIMode(GIMode gi);
SubShaderDescriptor Build();
}
// 2. 提供默认实现
class GLESSubShaderBuilder : ISubShaderBuilder
{
private SubShaderOptions _opts = new SubShaderOptions();
public ISubShaderBuilder WithRenderType(string type) { _opts.RenderType = type; return this; }
public ISubShaderBuilder WithRenderQueue(string queue) { _opts.RenderQueue = queue; return this; }
public ISubShaderBuilder UseComplexLit(bool complexLit) { _opts.ComplexLit = complexLit; return this; }
public ISubShaderBuilder WithPassParams(PassSubTargetParams p) { _opts.PassParams = p; return this; }
public ISubShaderBuilder WithKeywords(HashSet<ToggleDefinition> ks) { _opts.KeywordToggles = ks; return this; }
public ISubShaderBuilder WithGIMode(GIMode gi) { _opts.GiMode = gi; return this; }
public SubShaderDescriptor Build()
{
// 按照 opts 完整生成 descriptor
var result = CreateBase(_opts.RenderType, _opts.RenderQueue);
// … 按照 opts 里的字段往 passes 里添加 …
return result;
}
}
// 3. 使用者代码:
var descriptor = new GLESSubShaderBuilder()
.WithRenderType("Opaque")
.WithRenderQueue("Geometry")
.UseComplexLit(true)
.WithPassParams(myPassParams)
.WithKeywords(myKeywords)
.WithGIMode(myGiMode)
.Build();
通过这套方法之前的情况就变成了
1
2
3
4
5
6
7
8
9
10
11
12
13
var opt = new optBuilder()
.WithA(a)
.WithB(b)
....
.WithF(f)
.Build();
void FuncMain(para opt)
{
FuncA(opt);
FuncB(opt);
FuncC(opt);
}
参考网页
本文由作者按照 CC BY 4.0 进行授权