0

У меня есть один родительский типВыберите реализацию на основе типа объекта в Java

public class IObject{} 

и может иметь много подклассов (даже новые в будущем)

public class Object1 extends IObject{} 
public class Object2 extends IObject{} 
public class Object3 extends IObject{} 
... 
public class ObjectN extends IObject{} 

Затем, основываясь на типе этих объектов, я должен выполнять разные операции.

public class StrategyForObject1(){void do{}} 
public class StrategyForObject2(){void do{}} 
public class StrategyForObject3(){void do{}} 
... 
public class StrategyForObjectN(){void do{}} 

Так что я хочу от моего класса Context:

public Conext { 
    IObject o; 

    public void setObject(IObject o) { 
     this.o = o; 
    } 

    void logic() { 
     if (o instanceOf Object1) { 
      new StrategyForObject1().do(); 
     } 
     if (o instanceOf Object2) { 
      new StrategyForObject2().do(); 
     } 
     if (o instanceOf Object3) { 
      new StrategyForObject3().do(); 
     } 
     ... 
     if (o instanceOf ObjectN) { 
      new StrategyForObjectN().do(); 
     } 
    } 
} 

Так на основе типа для выполнения различных алгоритмов, но я хочу, чтобы быть расширяемой, как в шаблоне стратегии, если мне нужно, чтобы добавить новый суб- класс IObject, чтобы добавить новый класс StrategyForObject**N**, но не изменить класс Conext. В шаблоне стратегии мы должны указать Стратегию, но здесь мы должны сделать обратное: выбрать стратегию, основанную на типе объекта. Как сделать это на Java наилучшим образом?

Edit: IObject не может быть изменен, чтобы добавить дополнительные методы. Я должен отделить логику от данных, поэтому не желательно добавлять реализацию логики в класс Object1, например.

+0

Это сообщение может быть полезно для вас: http://stackoverflow.com/questions/255214/when-should-i-use-the-visitor-design-pattern/35406737 # 35406737 –

ответ

2

Во-первых, ваш класс IObject должен быть абстрактным, поскольку он предназначен только для расширения другими классами. Тогда вы можете объявить метод внутри него, который должен быть переопределен классами, которые наследуют от него, как это:

public abstract class IObject { 
    abstract void do(); 
} 

Тогда все классы, которые реализуют его необходимо переопределить этот метод с пользовательской логики:

public class Object1 extends IObject { 
    @Override 
    void do() { 
    //custom logic 
    } 
} 

Другими словами, вы должны положить do() внутри Object1 вместо StrategyForObject1.

Эта структура позволит вам вызвать do() на общий объект типа IObject, так как все дети IObject реализуют метод do(). Так что в вашем логическом методе, вы можете просто сделать это:

void logic(){ 
o.do(); 
} 
+0

В то время как это работает, для простого случая у него есть свои недостатки. Два основных, которые я вижу. Во-первых, вы должны включить бизнес-логику в свой объект. Во-вторых, вы можете реализовать только один вид логики. Шаблон посетителя позволяет использовать модульный и расширяемый подход. – Ulises

+0

@Ulises Я согласен с тем, что в зависимости от потребностей автора любое решение или мое может быть лучшим. Есть места и места для обоих. Ответ шаблона посетителя получил мой верхний номер – nhouser9

1

IObject может иметь абстрактный метод, do().

Тогда метод Context's logic() просто вызывает o.do().

Это классический пример полиморфизма.

+1

Вы просто скопировали мой ответ, но с меньшим объяснением. – nhouser9

+0

@ nhouser9 не спорь. У вас обоих будет голосом :) – Xelian

+0

Я медленный шрифт на своем телефоне, а иногда и короткий. @ nhouser9, ваш ответ будет улучшен путем упоминания (и, возможно, ссылки на) «полиморфизма». – user949300

1

Посмотрите на шаблон посетителя. Я думаю, что это именно то, что вы ищете.

Edit: Для уточнения:

import java.util.Arrays; 
import java.util.List; 

public class Test { 
    public static abstract class IObject { 
     public abstract void doSomeWork(StrategyVisitor strat); 
    } 

    public static class Object1 extends IObject { 
     @Override 
     public void doSomeWork(StrategyVisitor strat) { 
      strat.doWork(this); 
     } 
    } 

    public static class Object2 extends IObject { 
     @Override 
     public void doSomeWork(StrategyVisitor strat) { 
      strat.doWork(this); 
     } 
    } 

    public static class Object3 extends IObject { 
     @Override 
     public void doSomeWork(StrategyVisitor strat) { 
      strat.doWork(this); 
     } 
    } 

    public static interface StrategyVisitor { 
     void doWork(Object1 o); 

     void doWork(Object2 o); 

     void doWork(Object3 o); 
    } 

    public static void main(String[] args) { 
     List<IObject> objs = Arrays.asList(new Object1(), new Object2(), new Object3()); 

     StrategyVisitor visitor = new StrategyVisitor() { 
      @Override 
      public void doWork(Object1 o) { 
       System.out.println("Object1"); 
      } 

      @Override 
      public void doWork(Object2 o) { 
       System.out.println("Object2"); 
      } 

      @Override 
      public void doWork(Object3 o) { 
       System.out.println("Object3"); 
      } 
     }; 

     objs.stream().forEach(o -> o.doSomeWork(visitor)); 
    } 
} 

(см https://en.wikipedia.org/wiki/Visitor_pattern)

3

Я думаю, что вам нужно реализовать шаблон посетителя. В основном за то, что у вас есть это будет выглядеть примерно так:

interface IObjectVisitor { 
    void visit(IObject1 obj1); 
    void visit(IObject2 obj2); 
    ... 
    void visit(IObjectN objN); 
}  
interface IObjectVisitable { 
    void accept(IObjectVisitor visitor); 
} 
public abstract class IObject implements IObjectVisitable { 
    ... 
} 
public class IObject1 extends IObject { 
    public void accept(IObjectVisitor visitor) { 
     visitor.visit(this); 
    } 
} 
public class IObject2 extends IObject { 
    public void accept(IObjectVisitor visitor) { 
     visitor.visit(this); 
    } 
} 
... 
public class IObjectN extends IObject { 
    public void accept(IObjectVisitor visitor) { 
     visitor.visit(this); 
    } 
} 
public class SomeLogicIObjectVisitor implements IObjectVisitor { 
    void visit(IObject1 obj1) { 
     //something with obj1 
    } 
    void visit(IObject2 obj2) { 
     //something with obj2 
    } 
    ... 
    void visit(IObjectN objN) { 
     //something with objN 
    } 
} 

Тогда вы еще какая-то логика, чтобы применить к некоторым IObject так:

public void someLogic(IObject obj) { 
    SomeLogicIObjectVisitor visitor = new SomeLogicIObjectVisitor(): 
    visitor.visit(obj); 
} 

объектно-ориентированный мудрый, это лучший шаблон, который вы может реализовать. Причина в том, что он позволяет вам применять модульный и расширяемый подход, применяя правильное разделение проблем. Посмотрите на ответ, предоставленный @ nhouser9, например. Хотя определение abstract void do(); в IObject, похоже, работает на первый взгляд, вы бы ввели бизнес-логику внутри вашего объекта домена, который, скорее всего, там не принадлежит. Кроме того, если теперь вы рассмотрите какую-то другую логику, давайте назовем ее «logic2», теперь у вас нет выбора, кроме как создать abstract void do2(); для каждой реализации IObject и продолжать внедрять там бизнес-логику. С шаблоном посетителя реализация IObject не изменяется, и вы не внедряете какую-либо логику внутри IObjects, просто просто создайте нового посетителя Logic2IObjectVisitor и реализуйте логику каждой реализации IObject. И ты бы назвал это так:

public void someLogic2(IObject obj) { 
    Logic2IObjectVisitor visitor = new Logic2IObjectVisitor(): 
    visitor.visit(obj); 
} 
+0

Объяснение того, когда вы использовали шаблон посетителя вместо более простого полиморфизма, очень помогло бы этому ответу. – user949300

Смежные вопросы