2013-11-09 5 views
1

Code база засоренных кода, как это:Sad логика по типам

BaseRecord record = // some BaseRecord 
switch(record.source()) { 
    case FOO: 
     return process((FooRecord)record); 
    case BAR: 
     return process((BarRecord)record); 
    case QUUX: 
     return process((QuuxRecord)record); 
    . 
    . // ~25 more cases 
    . 
} 

, а затем

private SomeClass process(BarRecord record) { } 
private SomeClass process(FooRecord record) { } 
private SomeClass process(QuuxRecord record) { } 

Это делает меня очень грустно. Затем каждый раз, когда новый класс происходит от BaseRecord, мы должны преследовать всю нашу базу кода, обновляя эти операторы case и добавляя новые методы process. Такая логика повторяется везде, я думаю, слишком много, чтобы добавить метод для каждого и переопределить в классах. Как я могу улучшить это?

+1

Я предполагаю, что вы ищете являются дженериками. –

+2

На самом деле: generics plus interfaces –

+1

Собственно, полиморфизм, или шаблон посетителя –

ответ

1

Первое решение: старый старый полиморфизм.

Просто добавьте абстрактный метод process() к классу BaseRecord и переопределите его в каждом подклассе. Код таким образом, станет:

BaseRecord record = ...; 
record.process(); 

Если вы не можете добавить метод process() в класс BaseRecord (и его подклассов), а затем реализовать visitor pattern. Он оставит метод процесса вне класса BaseRecord, но каждый раз, когда вы добавляете новый подкласс, вы будете вынуждены изменить интерфейс Visitor и все его реализации. Таким образом, компилятор проверяет, что вы не забыли случай где-то в коммутаторе.

public interface RecordVisitor<T> { 
    T visitFoo(FooRecord foo); 
    T visitBar(BarRecord foo); 
    ... 
} 

public abstract class BaseRecord { 
    public abstract <T> T accept(RecordVisitor<T> visitor); 
} 

public class FooRecord extends BaseRecord { 
    @Override 
    public <T> T accept(RecordVisitor<T> visitor) { 
     return visitor.visitFoo(this); 
    } 
} 

public class BarRecord extends BaseRecord { 
    @Override 
    public <T> T accept(RecordVisitor<T> visitor) { 
     return visitor.visitBar(this); 
    } 
} 

Теперь вы просто должны реализовать RecordVisitor для каждого блока логики, описанной в вопросе:

RecordVisitor<Void> visitor = new ProcessRecordVisitor(); 
record.accept(visitor); 
+0

Как я объяснил (плохо) в моем вопросе, есть LOTS экземпляров блоков логики, подобных этому (например, 'switch (record.source()) {case FOO: return X ((FooRecord) Foo); case BAR: запись возврата X (BarRecord)); ...} 'и' X (запись FooRecord) {} ​​X (запись BarRecord) {} ​​'), но со многими различными методами' X'). Это не похоже на хорошее решение просто добавить все 'X' в базовый класс и переопределить. Я ищу еще лучшее решение. Надеюсь, что у меня есть смысл. – user2972231

+0

Вот почему в моем ответе говорится: если вы не можете добавить метод process() в класс BaseRecord, тогда реализуйте шаблон посетителя. Каждый блок логики преобразуется в отдельную реализацию Visitor. Для класса BaseRecord потребуется только один дополнительный метод, используемый каждым посетителем: 'accept (RecordVisitor visitor)' –

+0

Большое спасибо. Я, наконец, понимаю. – user2972231

0

Я думаю, что это поучительно:

package classplay; 

public class ClassPlay 
{ 
    public void say(String msg) { System.out.println(msg); } 

    public static void main(String[] args) 
    { 
    ClassPlay cp = new ClassPlay(); 
    cp.go(); 
    } 

    public void go() 
    { 
    A someClass = new C(); 
    say("calling process with double dispatch"); 
    someClass.dueProcess(this); 
    say("now calling process directly"); 
    process(someClass); 
    } 

    public void process(A a) 
    { 
    say("processing A"); 
    a.id(); 
    } 

    public void process(B b) 
    { 
    say("processing B"); 
    b.id(); 
    } 

    public void process(C c) 
    { 
    say("processing C"); 
    c.id(); 
    } 

    abstract class A 
    { 
    abstract public void id(); // { System.out.println("Class A"); } 
    public void dueProcess(ClassPlay cp) { cp.process(this); } 
    } 

    class B extends A 
    { 
    public void id() { System.out.println("Class B"); } 
    public void dueProcess(ClassPlay cp) { cp.process(this); } 
    } 

    class C extends A 
    { 
    public void id() { System.out.println("class C"); } 
    public void dueProcess(ClassPlay cp) { cp.process(this); } 
    } 
} 
Смежные вопросы