设置一个支持具有相同基本类型的多个对象的窗体的好方法是什么
本文关键字:类型 对象 窗体 是什么 方法 一个 支持 设置 | 更新日期: 2023-09-27 18:27:50
我有一个基类型(a),它有两个导数(B和C)。基类型不是抽象的。所以,我有三个物体。
B和C之间唯一的区别是它们都有一个额外的不同性质:
- B.Foo
- C.酒吧
现在我的代码中有这样的条件:
if(myObject is B)
myDatabindB.DataSource = ((B)myReport).Foo);
else if(myObject is C)
myDatabindC.DataSource = ((C)myReport).Bar);
在另一种方法中:
pnlSomePanel.Visible = myObject is B;
pnlSomeOtherPanel.Visible = myObject is C;
但你可以想象,当有一个新的类型时,我必须更新我所有的if-else语句。这违反了许多OO原则。
但问题是,我想不出一个好的、干净的解决方案来解决这个问题。你有解决这个问题的建议/想法吗?
编辑:如果重要的话,我使用MVP模式。
首先,你只问了三个问题,这很好——这会使解决问题的速度更快:)。您的代码非常通用,所以我只能提供通用的解决方案。
这里的大目标是增加类A、B和C的封装,以确保与A、B或C相关的任何内容都存储在这些类中,而不会移动到其他地方的if语句中。
我们可以将用于确定正确数据源的逻辑从Controller(它正在进行绑定)转移到您的报告中。此方法的名称应该是描述性的,如GetReportSubjectLine()。
class A{
<snip>
public virtual SomeDataType getDataSourceForViewType(){
throw new NotImplementedException()
}
}
class B{
<snip>
public override SomeDataType getDataSourceForViewType(){
return this.Foo;
}
}
class C{
public override SomeDataType getDataSourceForViewType(){
return this.Bar;
}
}
如果您想要制作不同的UI,并且仍然需要报告中的此类信息来生成您正在生成的任何图形视图,则此代码将是可重用的。
你提出的第二个问题没有好办法解决。我们总是可以将面板可见性移动到报告中,但这会大大增加耦合——一个类与另一个类的绑定程度。您的报告不应与特定视图绑定。
最好的解决方案是添加另一层间接——在本例中,是一个中间类,用于处理何时显示哪些面板的逻辑。这样,您的控制器就不必自己承担管理面板可见性的责任。
public class PanelVisibilityManager{
ICollection<Panel> ManagedPanels {get; set;}
//
public IDictionary<System.Type, ICollection<Panel>> Switchboard {get; set;}
public void TogglePanelsFor(System.Type item){
foreach(var panel in ManagedPanels){
panel.Visible=false;
}
foreach(var panel in Switchboard[item]){
panel.Visible=true;
}
}
希望这能有所帮助!
策略模式非常适合第一种情况
对于第二种情况,如果你有面板的一对一映射,你最终可能会得到一个静态只读Dictionary<类型,面板>面板(如果有许多类型)。WinForms中有一个选项卡控件,用于显示某些特定的选项卡以及
避免这种类型代码的方法之一是将决策响应能力转移到对象本身中。例如:
定义A.的收集
List<A> objects = new List<A>{new B(), new C()}
与其让if/else
在集合上使用foreach
,并在每个对象上调用在a中定义的虚拟方法,并在子对象中覆盖,如
virtual bool ThisIsMe(A objectToCheck){}
B和C通过检查objectToCheck
是否为其类型来覆盖此方法,并返回与其相关的true
或false
编辑
示例:
public class A
{
public virtual bool ThisIsMe(A objectToCheck){}
public virtual object GetData{}
}
public class B : A
{
public override bool ThisIsMe(A objectToCheck)
{
return objectToCheck is B;
}
public override object GetData()
{
return this.Foo;
}
}
public class C : A
{
public override bool ThisIsMe(A objectToCheck)
{
return objectToCheck is B;
}
public override object GetData()
{
return this.Bar;
}
}
现在不是if/else
,而是类似这样的东西:
foreach(A objA in objects)
{
if(objA.ThisIsMe(myObject))
{
myDatabindB.DataSource = objA.GetData();
break;
}
}
也可以用一些花哨的LINQ
指令来代替这一点。
希望这能有所帮助。
Dictionary<Type, Action>
怎么样?
然后你可以做这样的事情:
var myActors = new Dictionary<Type, Action<BaseClass>>();
myActors.Add(typeof(classA), DoSomethingWithA);
myActors.Add(typeof(classB), DoSomethingWithB);
...
Action actor;
if(myActors.TryGetValue(specialRetrievedOnlyAsBase.GetType(), actor))
{
ResetEverything();
actor(specialRetrievedOnlyAsBase);
}
else
{
// ToDo: What should happen if this type is not supported?
}
...
private void DoSomethingWithA(BaseClass)
{
var classAObject = (ClassA)BaseClass;
// ToDo: What should happen if classA arrives?
}
private void DoSomethingWithA(BaseClass)
{
var classAObject = (ClassB)BaseClass;
// ToDo: What should happen if classB arrives?
}