2 Stimmen

Wie erhalte ich eine Factory von spezifischen Klassen, die ein generisches Interface implementieren, ohne dass ich sie umwandeln muss?

Also, bitte übersetzen Sie dies und behalten Sie die gleichen HTML-Tags bei, wenn diese existieren, von en nach de:

Ich habe also eine Schnittstelle SuperType und eine Reihe von Implementierungsklassen TypeA, TypeB und so weiter. Ich habe auch eine Top-Level-Schnittstelle, die eine parametrisierte Methode hat:

public interface UsedByProductThing {
    public T doStuff(T one);
}

Ich habe eine Fabrik (siehe unten), die Objekte erzeugt, die GeneralProduct implementieren:

public interface GeneralProduct {
    T doSomething(T input);
}

Hier ist die Implementierung von ProductA:

public class ProductA implements GeneralProduct {
    UsedByProductThing in;

    public ProductA(UsedByProductThing in) {
        this.in = in;
        in.doStuff(new TypeA());
    }

    @Override
    public TypeA doSomething(TypeA input) {
        return null;
    }
}

Und nun die betreffende Fabrik:

public class GeneralFactory {
    public static  GeneralProduct createProduct(
            int type, UsedByProductThing in) {
        switch (type) {
        case 1:
            return (GeneralProduct) new ProductA((UsedByProductThing) in);
            // an diesem Punkt möchte ich idealerweise ein "new ProductA(in)" zurückgeben
            // ohne Umwandlung
            // oder zumindest ohne die Umwandlung des Arguments.
        default:
            throw new IllegalArgumentException("Typ unbekannt.");
        }
    }
}

Wie kommentiert, möchte ich, dass die Fabrikmethode keine Umwandlung verwendet. Mir ist klar, dass der Rückgabetyp GeneralProduct sein muss, aber ich kann mir keinen Weg vorstellen, wie ich die Umwandlung (und sie gibt mir auch eine "unchecked cast"-Warnung) vermeiden kann. Auch fällt mir keine Möglichkeit ein, die Umwandlung des Arguments zu umgehen. Ich kann den gesamten Code umstrukturieren, wenn es notwendig ist, um die "unsichere" Umwandlung an dieser Stelle loszuwerden. Können Sie mir einen Weg zeigen, der hier schön und problemlos wäre?

Bitte bearbeiten Sie auch meine Frage nach Ihren Wünschen - ich weiß nicht, wie ich das Problem in der Überschrift korrekt ansprechen soll.

Vielen Dank!

4voto

Peter Lawrey Punkte 511323

Sie können das Casten nicht vermeiden, weil

  • Sie in haben, das vom Typ UsedByProductThing ist, das Sie in ein UsedByProductThing umwandeln möchten und der Compiler nichts darüber weiß, dass T ein TypeA ist
  • ProductA ist GeneralProduct und auch hier weiß der Compiler nicht, dass T ein TypeA ist.

Der einzige Weg, um Cast zu vermeiden, besteht darin, T durch TypeA zu ersetzen.

    public static GeneralProduct createProduct(
            int type, UsedByProductThing in) {
        switch (type) {
            case 1:
                return new ProductA(in);
            default:
                throw new IllegalArgumentException("Typ unbekannt.");
        }
    }

0voto

Matt Punkte 11307

Ich bin mir nicht sicher, ob es einen sauberen Weg gibt, dies zu tun. Außerdem denke ich, dass jegliches Casting auf die Art und Weise, wie Sie es tun, ohnehin unsicher ist, da jemand einen "Typ"-Wert übergeben könnte, der nicht mit dem "in"-Wert kompatibel ist.

Das gesagt, solche inhärenten unüberprüften Casts sind häufig bei der Verwendung von Generika. Sie sollten sie vermeiden, wenn möglich, aber manchmal können Sie es nicht und sollten einfach die Annotation hinzufügen, um die Compilerwarnung wirklich loszuwerden.

@Suppress("unchecked")

Alternativ warum nicht einen Builder-Ansatz wählen?

public interface Builder {
    public GeneralProduct createProduct(UsedByProductThing thing);
}

public class BuilderFactory {
    public static  Builder createBuilder(Class clazz) {
       if (clazz.equals(ProductA.class)) {
          return new (Builder) ProductABuilder();
       }
       ...
    }
}

Und dann verwenden Sie es folgendermaßen (angenommen, Sie haben eine Builder-Implementierung erstellt):

Builder builder = BuilderFactory.createBuilder(ProductA.class);
UsedByProductThing thing = ...;
ProductA product = builder.createProduct(thing);

0voto

Grim Punkte 4303

Keine Rückkehr

"GeneralProduct"

, besser du gibst zurück

"GeneralProduct"

, also brauchst du das Ergebnis nicht zu casten.

Aber jedenfalls musst du den Parameter für "ProductA" casten!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X