Паттерн для instanceof

139
27 октября 2017, 11:26

Есть несколько классов, далее идет проверка классов через instanceof, если передали такой класс тогда выполнить такие то действия. Какой паттерн можно использовать.

getParams(SomeClass some) {
if (some instanceof SomeNoth) {
... 
... 
... 
... }
if (some instanceof SomeNoth2) {
... 
... 
... 
... }
if (some instanceof SomeNoth3) {
... 
... 
... 
... }
if (some instanceof SomeNoth4) {
... 
... 
... 
... }
if (some instanceof SomeNoth5) {
... 
... 
... 
... }
Answer 1

Так как вы настаиваете на примере, приведу простой для понимания. Наши тестовые классы:

public class Test1 {
    public void method1() { System.out.print("Test1.method1"); }
}
public class Test2 {
    public void method2() { System.out.print("Test2.method2"); }
}

Далее, небольшая архитектура:

public interface IHandler {
    void run(Object obj);
    boolean isTypeof(Object obj);
}

Под неё делаем две реализации хандлеров:

public class Test1Handler implements IHandler {
    @Override
    public void run(Object obj){
        Test1 test = (Test1)obj;
        // Здесь любой код...
        test.method1(); // для примера
    }
    @Override
    public boolean isTypeof(Object obj){
        return obj instanceof Test1;
    }
}
public class Test2Handler implements IHandler {
    @Override
    public void run(Object obj){
        Test2 test = (Test2)obj;
        // Здесь любой код...
        test.method2(); // для примера
    }
    @Override
    public boolean isTypeof(Object obj){
        return obj instanceof Test2;
    }
}

Всё, архитектура готова, реализация есть, теперь можно всё свернуть в один универсальный метод:

public class ServiceChecker {
    private static ServiceChecker instance;
    private List<IHandler> handlers = new ArrayList<IHandler>();
    public ServiceChecker(){
        handlers.add(new Test1Handler());
        handlers.add(new Test2Handler());
    }
    public static ServiceChecker getInstance(){
        if(instance==null){
            instance = new ServiceChecker();
        }
        return instance;
    }
    public void check(Object some){
        for(IHandler handler : handlers){
            if(handler.isTypeof(some)){
                handler.run(some);
                break;
            }
        }
    }
}

Теперь можно смело использовать:

ServiceChecker.getInstance().check(new Test2());
ServiceChecker.getInstance().check(new Test1());

Что вообще этот подход вам даст:

  1. Вы разделите ваше полотно на кучу классов, что в разы удобнее содержать и дополнять.
  2. Вы сможете составить огромную "библиотеку" хандлеров. Лично я такое использовал для преобразования типов в Unity3d, своего рода универсальный парсер. Универсальный он потому, что добавлять и удалять хандлеры не составляет труда, как вы заметили.

Является ли это паттерном? Честно скажу - я не знаю. Скорее всего, нечто такое уже придумали.

Answer 2

Можно сделать изящно и красиво - использовать фабрику. А именно:

Map<Class, Runnable> actions = new HashMap<>();  
....  
void registrationAction(Class<?> cl, Runnable action){
   actions.put(cl, action);
}
void actionOn(SomeClass cl){
   actions.get(cl.getClass()).run();
}
Answer 3

Начиная с Java 7 можно использовать String в switch, следовательно можно хакнуть так:

getParams(SomeClass some) {
   String clzName=some.getClass().getSimpleName();
   switch(clzName) {
      case "SomeNoth":
        break;
      case "SomeNoth2":
        break;
      //blah-blah
   }
}

Update

Для поборников чистоты можно сделать так:

interface Doable {
    public void doSome();
}
class ExSomeClass extends SomeClass implements Doable {
    public void doSome() {
        //blah-blah
    }
}
class ExSomeNoth extends SomeNoth implements Doable {
    public void doSome() {
        //blah-blah
    }
}
class ExSomeNoth2 extends SomeNoth2 implements Doable {
    public void doSome() {
        //blah-blah
    }
}

В итоге ваш метод будет работать так:

getParams(Doable some) {
   some.doSome();
}

Никаких кастов, instanceof и упаси боже модификации исходных классов.

Answer 4

Что бы действовать подобным образом, надо иметь очень веские на то причины. Стандартным решением будет объявить интерфейс с методом getParams и имплиментировать его для всех ваших классов.

public interface SomeNothInterface{
    public Params getParams();
}
public class SomeNoth implements SomeNothInterface{
....
    public Params getParams(){
        //логика
    }

И вызывать так

public Params getParams(SomeNothInterface someClass) {
    return someClass.getParams();
}
Answer 5

У вас тут самый настоящий антипаттерн. Правильный объектно-ориентированный код работает с максимально узкой абстракцией и ему не требуется проверять конкретный тип. Если такая необходимость вдруг появилась, значит вы нарушаете принципы SOLID. К тому же, instanceof ещё и медленный оператор.

READ ALSO
Файл настроек websphere

Файл настроек websphere

Ну удается запустить websphere application server после изменения настроек памяти, начальный размер кучи и максимальный я оставил поля пустыми, не запускается...

157
Список популярных библиотек CAS на Java

Список популярных библиотек CAS на Java

Например: JAS (Java Algebra System)Вопрос в том, какие еще библиотеки существуют для использования? И какие из них можно использовать на Android?

176
Чем опасна слепая инициализация?

Чем опасна слепая инициализация?

Прошу объяснить, чем опасна "слепая инициализация" на каком-нибудь примере из практики?

161
добавление ресурсов в jar файл

добавление ресурсов в jar файл

Господа знатоки подскажите

239