2015-01-15 2 views
0

Я довольно новичок в программировании на Java, и у меня есть вопрос дизайна. На данный момент я получил следующее:design issue generics/factory/abstract class

public class MyFactory { 

    private MyFactory(){ 
     //hidden constructor 
    } 

    public static ImageFilter getInstance(String filterType){ 
     if(filterType == “foo“){ 
      return new FooFilter(); 
     } 
     return null; 
    } 
} 

public abstract class ImageFilter { 
    public abstract Bitmap filterImage(byte[] data); 

    //some other stuff 
} 

public class FooFilter extends ImageFilter { 
    public C filterImage(byte[] data){ 
     //want to apply filterImageA or filterImageB depending what I put in 
     //at (*) and (**) 
    } 

    private A filterImageA(byte[] data){ 
     // 
    } 

    private B filterImageB(byte[] data){ 
     // 
    } 
} 

void main(byte[] data) { 
    ImageFilter bar = MyFactory.getInstance(“foo“); 
    BitmapType1 myBitmap = bar.filterImage(byte[] data); //(*) 
    BitmapType2 myBitmap2 = bar.filterImage(byte[] data); //(**) 
} 

В основном методе я знаю, каков результирующий тип. Если это BitmapType1, я должен применить filterImageA. Если это BitmapType2, то я должен использовать filterImageB. Есть ли общий способ сделать это? Я читал о дженериках, но понятия не имею, как их использовать в этом конкретном случае. Надеюсь, это не слишком смущает. Возможно, весь подход - дерьмо. Не стесняйтесь предлагать лучший!

ответ

1

@ ответ Димов прав но вы можете также сделать больше ImageFilter.. Общий вид:

public class MyFactory { 

    private MyFactory(){ 
     //hidden constructor 
    } 

    public static ImageFilter getInstance(String filterType){ 
     if(filterType == “foo“){ 
      return new FooFilter(); 
     } 
     return null; 
    } 
} 

public abstract class ImageFilter { 
    public abstract <T extends Bitmap> T filterImage(byte[] data, Class<T> clazz); 

    //some other stuff 
} 

public class FooFilter extends ImageFilter { 
    public <T extends Bitmap> T filterImage(byte[] data, Class<T> clazz){ 
     if (BitmapType1.class.isAssignableFrom(clazz)) { 
      return this.filterImageA(data); 
     } else if (BitmapType2.class.isAssignableFrom(clazz)) { 
      return this.filterImageB(data); 
     } 
     return null; // or better throw runtime exception 
    } 

    private BitmapType1 filterImageA(byte[] data){ 
     // 
    } 

    private BitmapType2 filterImageB(byte[] data){ 
     // 
    } 
} 

void main(byte[] data) { 
    ImageFilter bar = MyFactory.getInstance(“foo“); 
    BitmapType1 myBitmap = bar.filterImage(byte[] data, BitmapType1.class); 
    BitmapType2 myBitmap2 = bar.filterImage(byte[] data, BitmapType2.class); 
} 

Примечание: если либо BitmapType1 наследуется (напрямую или нет) от BitmapType2 или наоборот, вам нужно будет выбрать наиболее конкретный класс иерархии первой:

 if (BitmapType1.class.isAssignableFrom(clazz)) { // BitmapType1 type more concrete 
      return this.filterImageA(data); 
     } else if (BitmapType2.class.isAssignableFrom(clazz)) { // BitmapType2 type more general 
      return this.filterImageB(data); 
     } 
+0

Я пробовал это по-своему, но у меня получилось сообщение об ошибке вроде: '' несовместимые условные типы операндов Class и Bitmap ". Единственным общим суперклассом, совместно использующим оба типа изображений, является Object. Может ли это быть проблема? Можно ли обойти это? –

+0

Это ошибка компиляции? В какой строке возникает ошибка? Если вы используете Eclipse, см. [Этот вопрос] (http://stackoverflow.com/questions/2551337/instanceof-incompatible-conditional-operand-types), особенно второй ответ. Это может быть полезно. –

+0

Да, это ошибка времени компиляции. Я использую Eclipse, но Bitmap импортируется. Просто для удовольствия я попробовал что-то вроде 'T test = null' и' if (clazz instanceof test) ... ', и ошибка исчезла. К сожалению, это условие не изменилось. Я не знаю, действительно ли я понимаю концепцию класса Class clazz'. Действительно ли это экземпляр T? –

0

Вместо filterImageA и filterImageB, создать два различных фильтров: один, имеющий это filterImage делать то, что filterImageA делает, а другой для filterImageB. Затем в вашем main, где вы знаете, хотите ли вы «A» или «B», получите правильный фильтр по имени с фабрики и вызовите на нем filterImage.

+0

Это хорошая идея. Это просто filterImageA и filterImageB делают почти то же самое, и я хотел бы, чтобы они были сгруппированы вместе. По сути, это один и тот же фильтр, применяемый в двух разных форматах файлов с использованием разных буферов и так далее. Извините за то, что вы недостаточно ясно! –

+0

Вы можете сделать их обычным суперклассом, который будет содержать общую логику и переопределить только части, которые отличаются в конкретных подклассах. – Dima

0

У меня есть несколько замечаний по этому фрагменту кода:

  • MyFactory класса может иметь метод регистрации как add(String bitmapType, String filterType, ImageFilter filter), так что это может быть динамичными. Создать компонент, который содержит два значения в качестве ключа для Map (быть осторожным equals() и hashCode(), чтобы держать их, и вы сделали. Эффективно, вы будете иметь ImageFilter для каждого отдельного bitmapType и фильтров обработки.
  • Это личный выбор, но я бы написать ImageFilter как интерфейс и - при необходимости - добавить AbstractImageFilter используя метод шаблона для инкапсуляции до/общего поведения
+0

Спасибо за ваши замечания! Я изменю это. –