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

但是,我担心我过度分散了这段代码,它可能会膨胀太多。也许我不应该太害怕本质上是一种方法接口,但我想在走这条路之前看看我是否缺少设计模式?(唯一出现在我脑海中但不太合适的是装饰器复合模式)

更新

所有属性都是唯一类型。

最终,这是一种依赖注入的形式。代码太乱了,现在不能使用像 Ninject 这样的东西,但最终我什至可以摆脱其中的一些并使用注入容器。除了设置变量之外,目前还有一些逻辑正在完成。这都是遗留代码,我只是想一点一点地清理它。

4

4 回答 4

1

当您面对 switch 语句和类型转换时,访问者模式是标准的解决方案。您的每种情况的代码将进入访问者类中的单独方法。您的每个类将只实现一个接口——一种accept接受访问者的方法。你最终会得到比现在更多的代码,但它会读起来更清晰。

于 2012-08-23T05:52:41.167 回答
1

基本上,您想让演员(使用 setProp 方法的类型)成为相同类型的“演员”,并使属性(prop1...n)成为相同类型的“道具”。这会将您的代码减少到

actor.setProp(prop)

如果您想避免使用instanceOf,我能想到的唯一方法是使用访问者模式,使“道具”成为访问者。我也会使用模板方法让我的生活更轻松。在 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);

...这是超级好!

于 2012-08-23T07:23:01.360 回答
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 模式来构建属性......等等。

于 2012-08-22T20:45:41.850 回答
1

我认为答案取决于您首先要重构代码的原因。

  • 如果您想完全摆脱 switch 块,那么您必须使用一种方法实现一个接口,该方法采用三个参数。每个班级都必须弄清楚哪些论点适用以及如何处理这些论点。
  • 如果您想减少代码总量,那么我不确定添加特定于类的属性设置逻辑是否比原始 switch 语句更少的代码
  • 如果您想利用编辑器的代码完成功能来插入具有正确数量的属性/参数的正确方法,那么只需在每个类上实现正确的方法并完全避免接口
于 2012-08-22T21:41:31.850 回答