2012-08-22 21 views
4

我重构这是通过一个case语句一遍又一遍地做接近同样的事情,一些遗留代码:接口地狱或可接受的设计?

switch(identifier) 
    case firstIdentifier: 
     (SomeCast).SetProperties(Prop1,Prop2,Prop3); 
     break; 
    ... 
    case anotherIdentifier: 
     (SomeDifferentCast).SetProperties(Prop1, Prop2, Prop3); 
     break; 

所以,我试图创建一个独特的界面,使这可能成为

(SameInterfaceCast).SetProperties(Prop1,Prop2,Prop3); 

但是,我发现有些项目甚至没有使用所有的属性。于是,我开始想的更多的东西是这样的:

if(item is InterfaceForProp1) 
    (InterfaceForProp1).SetProp1(Prop1); 
if(item is InterfaceForProp2) 
    (InterfaceForProp2).SetProp2(Prop2); 
if(item is InterfaceForProp3) 
    (InterfaceForProp3).SetProp3(Prop3); 

,你可以创建这样一个类:

public class MyClassUsesProp2And3 : InterfaceForProp2, InterfaceForProp3 

不过,恐怕我过于碎片化这个代码,它可能气球太多了。也许我不应该太担心本质上是一种方法的接口,但我想看看在我走下这条路之前是否错过了一种设计模式? (即突然出现在我的脑海里,但都不太合适人选的唯一的人的DecoratorComposite模式)

UPDATE

所有属性是唯一的类型。

最终,这是一种依赖注入的形式。该代码太乱了,现在使用类似Ninject的东西,但最终我甚至可能会摆脱其中的一些并使用注入容器。目前还有一些逻辑正在被完成,而不仅仅是设置一个变量。这是所有遗留代码,我只是试图一点一点地清理它。

+0

属于同一类型的Prop1,Prop2和Prop3吗?因为我几乎认为你想为InterfaceForProp1,InterfaceForProp2和InterfaceForProp3创建一个具有SetProp()方法的超类,该方法接受任何类型的参数Prop1,Prop2和Prop3。 – dmn

+0

也许Prop1,Prop2和Prop3是尚未由对象表示的域概念的属性。这可能会简化您的界面。 – neontapir

+0

@dmn我刚刚更新了我的问题,添加了所有类型都是不同的。如果他们都一样,那么这将是蛋糕。 –

回答

1

基本上你想让actor(类型与setProp方法)相同的类型'Actor'并使属性(prop1 ... n)具有相同类型'Prop'。这将降低代码到

actor.setProp(prop) 

如果你想避免使用}这种,我能想到的就是去与访问者模式的唯一途径,使“道具”的游客。我也会使用模板方法让我的生活更轻松。在Java中,我会让它看起来像这样(对于两种实际类型的Prop)。

class Actor { 

    protected void set(Prop1 p1) { 
     // Template method, do nothing 
    } 

    protected void set(Prop2 p2) { 
     // Template method, do nothing 
    } 

    public void setProp(Prop p) { 
     p.visit(this); 
    } 

    public interface Prop { 
     void visit(Actor a); 
    } 

    public static Prop makeComposite(final Prop...props) { 
     return new Prop() { 

      @Override 
      public void visit(final Actor a) { 
       for (final Prop p : props) { 
        p.visit(a); 
       } 
      } 
     }; 
    } 

    public static class Prop1 implements Prop { 
     public void visit(Actor a) { 
      a.set(this); 
     } 
    } 

    public static class Prop2 implements Prop { 
     public void visit(Actor a) { 
      a.set(this); 
     } 
    } 
} 

这允许你做的东西是这样的:

ConcreteActor a = new ConcreteActor(); 
    Prop p = Actor.makeComposite(new ConcreteProp1(42), new ConcreteProp2(-5)); 
    a.setProp(p); 

...这是超漂亮!

+0

如果我正确地读了这个,我需要尽可能多的调用,因为我有属性,但它避免了额外的if:'actor.setProp(Prop1); actor.setProp(Prop2);'etc?我知道访问者的模式,但从未使用过它,直到现在,我对于实现的含义非常模糊。如果我对这个用法是正确的,我确实很喜欢这个......但是我目前对属性类没有控制权。不过,我会做一个更重要的重构,以便以后可以做到这一点。给你的支票,因为你解释这是最好的,这是我的感觉是正确的答案(即使我不能使用它) –

+0

谢谢你的支票!这不是Visitor的传统用途,但它解决了手头的问题。是的,你必须为每个新属性添加一个新的set(),但是如果你添加一个新属性,所有你需要的是将它作为一个新的虚拟模板方法添加到基类Actor上,然后为需要能够响应新属性的Actor的子类。这几乎是最小的变化情况。 –

+0

我清理了代码,并使它更具体一些,并增加了一种从道具上制作复合材料的方法。即使您无法控制实际的属性类,您仍然可以在重构时将它们包装在此结构中。 –

1

我不知道是否有一个“正确”的答案,但这是我会做的。

class Properties { 
    prop1 
    prop2 
    prop3 
} 

interface PropertySetable { 
    setProperties(Properties prop); 
} 
public class MyClassUsesProp2And3 implements PropertySetable { 
    setProperties(Properties prop) { 
     //I know I need only 2 and 3 
     myProp2 = prop.prop2; 
     myProp3 = prop.prop3; 
    } 

} 

在调用函数中,你不应该有一个强制转换。

someFunc(..., PropertySetable, Properties,...) { 
     PropertySetable.setProperties(Properties); 
} 

这是基本结构。

你应该封装属性 - 使属性私人并有相关的构造函数。或者使用Builder模式来构建属性...以及更多..

+0

看,但你仍然在这里做着同样的事情。我真的想避免传递甚至没有使用的变量。 –

+1

不是真的......我更喜欢让类决定他们需要什么......而不是调用代码。你反对传递'Properties'对象?对我来说,要求班上需要什么,然后把它交给他们似乎很浪费。把所有东西都拿走吧 - 并且拿出你需要的东西。由于可维护性,它比传递单个属性更好。如果你传递指针/引用,然后性能/内存明智,它也不是问题。 – Chip

+0

+1因为我对它的想法越多,这种方法也适合。不过,访客模式更好。这就是为什么我给它的复选标记 –

1

我认为答案取决于您为什么要首先重构代码。

  • 如果你想完全摆脱开关块,那么你将不得不实现一个接口与一个方法接受三个参数。每个班级都必须弄清哪些参数适用以及如何处理这些参数。
  • 如果您想要减少代码的总量,那么我不确定添加特定于类的属性设置逻辑的代码是否小于原始开关语句的代码
  • 如果要利用编辑器的代码完成功能插入了正确的号码属性的正确方法/ ARGS然后只执行关于每一类的正确的方法(或多个),并避免界面共
+0

国际海事组织,你的第三个选项根本不是一个理由。我更改代码的主要原因是为了使代码更易于维护和可读,使其更加牢固。访问者模式是这样做的最佳方式。 –

1

visitor pattern是标准溶液时你面对switch语句和类型转换。您的每个案例的代码将在访问者课程中进入单独的方法。而且你的课程将只实现一个接口 - 一种接受访问者的方法accept。你会得到比现在更多的代码,但它会读得更清晰。