这是我的计划:
class Program
{
//DESIGN 1
abstract class AFoo
{
public string Bar { get; set; }
public abstract string SayHi();
}
class LoudFoo : AFoo
{
public override string SayHi()
{
return this.Bar.ToUpper();
}
}
class QuietFoo : AFoo
{
public override string SayHi() { return this.Bar.ToLower(); }
}
//DESIGN 2
class Foo{
public string Bar { get; set; }
public Func<Foo, string> SayHi { get; set; }
}
static void Main(string[] args)
{
//USING DESIGN 1
var quietFoo2 = new QuietFoo{ Bar = "Mariane"};
var loudFoo2 = new LoudFoo{ Bar = "Ginger"};
Console.WriteLine(quietFoo2.SayHi());
Console.WriteLine(loudFoo2.SayHi());
//USING DESIGN 2
var quietFoo = new Foo
{
Bar = "Felix",
SayHi = (f) => { return f.Bar.ToLower(); }
};
var loudFoo = new Foo
{
Bar = "Oscar",
SayHi = (f) => { return f.Bar.ToUpper(); }
};
Console.WriteLine(quietFoo.SayHi(quietFoo));
Console.WriteLine(loudFoo.SayHi(loudFoo));
}
}
Run Code Online (Sandbox Code Playgroud)
我可以完成"同样的事情" - 实际上不完全相同的事情,但类似的事情走两条不同的路线.
设计1)我可以创建一个抽象类,强制该类的实现者如何SayHi()
- 要么 -
设计2)我可以创建一个类来定义一个SayHi属性,它是一个函数.(我称之为代表 - 但我不确定这是否是正确的术语)
设计1困扰我,因为它可以导致课程的丰富
然而....
设计2困扰我,因为当我必须让Foo实际上是SayHi()时感觉多余.
felix.SayHi(felix)
Run Code Online (Sandbox Code Playgroud)
我的问题是使用Design 1还是Design 2--或者两者都不是更好.当我说得更好时,我说的是能够维持我的程序更实用.当我创建不同的类时,我遇到了这个问题,这些类将用于从不同的云API(Google Drive,Box.com,DropBox)下载文件 - 起初我创建了单独的类,但后来我走了另一条路.
当谈到这些类型的设计选择时,我发现根据您尝试建模的问题域来考虑对象会有所帮助.您已经将LoudFoo和QuietFoo显示为单个行为的不同,但这是一个故意简化的示例.在实际系统中,您可能有令人信服的理由将两个对象视为概念上不同的.
在前一版本中,SayHi是类行为的一个内在部分,如果该行为的性质以某种方式与其内部状态相互作用,这是恰当的.也许SayHi的实现依赖于特定于派生类类型的对象的属性.
在后一版本中,SayingHi更像是一个可以分发给各种实例的工具.当没有其他理由来区分不同类型的Foo实例时,这是合适的.
Stream是前一种模式的一个很好的例子,它提供的各种方法对于流操作的本质是固有的.各种派生类将使用不同的状态来实现其方法.
Comparer是后一种模式的一个很好的例子,其中许多不同的对象类型想要使用比较的概念来操作.除了想要使用此特定类型的行为之外,使用此功能的类不需要具有任何其他共同点.
关于提出这个问题的具体应用,那么多类方法又有什么尴尬?如果存在冗余蔓延,则可能表明可以以更好地模拟问题的不同方式考虑责任.如果不了解有关特定问题的其他详细信息,很难说更多,但很可能一个好的方法是你提出的两个方法的组合,一些单个类负责操作的排序和一个单独的层次结构(或一组接口实现) )实施特定于每项服务的操作.本质上,接口(或基类)将分别传递的所有各种代理组合在一起.这类似于StreamReader如何获取Stream并使用在Stream上运行的其他行为来增强它.
| 归档时间: |
|
| 查看次数: |
2017 次 |
| 最近记录: |