Тип возврата из шаблона фабрики Java

0 A Gilani [2014-01-18 03:01:00]

Это может быть очень простой вопрос с очень очевидным ответом, но мне трудно понять это.

Как узнать тип возвращаемого метода класса с использованием шаблонов java factory. например, смотря на код ниже..., каков будет тип возвращаемого вызова метода и как его правильно направить... а также как написать javadoc также для классов.

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

У меня есть интерфейс

public interface myInterface
{
     public Object doA();
     public Object doB();
}

и конкретные классы, как следует

public class concerete1 implements myInterface
{
public concerete1() {
}

@override
public Object doA()
{ return new String("Hello"); }

@override
public Object doB()
     { return "hello".getBytes(); }

}

а также

public class concerete1 implements myInterface
{
public concerete2() {
}

@override
public Object doA()
{ return "hello".getBytes(); }

@override
public Object doB()
{ return new String("Hello"); }

}

и мой заводский класс, как следует

public class factory
{
     private myInterface mi;

     public myInterface actionProducer(String choice)
     {
           switch(choice)
           {
           case "a":
                 mi = new concerete1();
                 break;
           case "b":
                 mi = new concerete2();
                 break;
           }
           return mi;
     }
}

и мой класс тестового бегуна следующий

String result = factory.actionProducer("a").doA();

java javadoc factory-pattern


4 ответа


6 Решение user2357112 [2014-01-18 03:08:00]

Вам не нужно явно проверять динамический тип возвращаемого значения заводского метода. Статический тип должен рассказать вам все, что вам нужно знать. Это означает, что тип возврата должен быть таким же конкретным, каким должен быть, чтобы рассказать вам, что вы можете сделать с объектом. Например, фабричный метод, который делает карты различной реализации, должен возвращать Map:

public interface MapFactory {
    public Map makeMap();
    ...
}

Независимо от того, является ли Map HashMap или TreeMap или ConcurrentSkipListMap, вы можете использовать методы Map для взаимодействия с ней. Если окажется, что вам нужно вызвать ceilingKey, который не является методом Map, у вас есть проблема с дизайном.

В вашем случае, ваши фабричные методы не имеют никакого смысла, так как нет более конкретного типа для возврата, чем Object, и вы ничего не можете сделать с возвращаемыми значениями за пределами API от Object. Более разумная фабрика будет возвращать объекты, которые могут взаимодействовать одинаково, независимо от того, как реализованы объекты.


1 J Ellis [2014-01-18 03:29:00]

Тип возврата будет Object во всех случаях. Я не знаю, к чему вы клоните, но если это String, то кастинг в String из массива байтов невозможен. Вместо этого вам придется использовать один из конструкторов класса String ("String result = new String (factory.actionProducer(" a "). DoA());"). Если вы вызывали "doB()" (и, таким образом, получая String как объект), вы могли бы преобразовать его в строку либо путем ее литья ("String result = (String) factory.actionProducer(" a "). DoA(); ") или путем вызова метода возвращаемого объекта toString() (" String result = factory.actionProducer("a"). doB(). toString(); ").

Javadoc для этих методов будет описывать каждый из них как возвращающий объект, потому что это то, что они делают.

Короче говоря, я бы изменил возвращаемые типы "doA()" и "doB()" на то, что они фактически возвращают (массив String или byte), но, возможно, это не вариант того, что вы пытаетесь сделать. Некоторый дополнительный контекст может помочь в более детальном ответе.

EDIT: Извините, я не понимал, что типы возвращаемого массива String и byte были перевернуты по двум реализациям. В ответе я описал "doA()" как возвращающий массив байтов и "doB()" как возвращающий String, и я считаю, что те, которые были задействованы в реализации, которую вы используете в вашем примере (Concrete1). Однако все остальное в значительной степени стоит.


1 MGorgon [2014-01-18 03:11:00]

Вы не должны интересоваться реальным заводским типом продукта. Абстрактная фабрика построена для факторинговых объектов с общим интерфейсом/абстрактным суперклассом. Итак, если у вас будет

public abstract class Animal {
     public void eat();
     public String foo();
}

и классы-разработчики:

public class Dog extends Animal {
    public void eat() {
     //stuff here
    }
    public String foo() {
        return "howgh";
    }
}

public class Cat extends Animal {
    public void eat() {
     //stuff here
    }
    public String foo() {
        return "meow";
    }
}

Интерфейс вашей фабрики будет выглядеть примерно так:

public interface AnimalFactory {
     public Animal createAnimal();
}

И бетонный завод будет

public class CatFactory implements AnimalFactory {
     public Cat createAnimal(){
         return new Cat();
     }
}


public class DogFactory implements AnimalFactory {
     public Dog createAnimal(){
         return new Dog();
     }
}

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

Animal awesomeAnimal = catFactory.createAnimal();
System.out.println(awesomeAnimal.foo());

выход будет "мяуком". Это возможно, потому что все продукты являются подклассами общего интерфейса (Animal здесь).


0 itmustbesid [2014-01-18 03:19:00]

Самый простой ответ заключался бы в том, чтобы объявить "результат" как объект, а затем принудительно применить бросок и просто надеяться, что вы правильно поняли: если вы этого не сделаете, вы получите ошибку во время выполнения:

 Object obj = factory.actionProducer("a").doA();
 String str = (String) obj;

Однако в вашем примере doA() возвращает либо String, либо byte [], в зависимости от выбора реализации, поэтому это не удастся для "b" и преуспеть для "a". Может быть, это была опечатка в вопросе?

При немного более четком определении ваших целей использование общих типов может помочь, но его трудно сказать без дополнительной информации.