Klasa tworzona o dynamicznie ładowany interfejs

0

Witam,
chcę zrobić dynamiczne ładowanie klas i ich interfejsu.
Wstępnie ładuję interfejs, następnie klasy. Dalej chce stworzyć klasę na podstawie tego intefejsu:

...
Class cls = cl.loadClass("Test1Class");
ZaladowanyInterfejs klasa = (ZaladowanyInterfejs) cls.newInstance();

Ale przecież dynamicznie ładuje interfejs (nie musze wiedzieć jak sie nazywa) więc jak moge dokonać to co robi powyższy zapis?

0

niemozesz - w refleksjach dzialaja zwykle mechanizmy jak bys pisal zwyczajnie kod (poza dostepem do pol chronionych i prywatnych, mozna to ominac), no ale nigdy przenigdy nie mozesz instancjonowac interfejsu, wiec newInstance() zawsze zwroci bodajze InstantiationException.

0

ej sory nie zauwazylem ze ladujesz klase in instancjonujesz klase i tylko chcesz rzutowac na interfejs
to co napisalem powyzej to blad

ogolnie jesli interfejs ladujesz rowniez dynamicznie, to nie mozesz bezporeednio jego nazwy uzyc w kodzie, poniewaz zwyczajnie nie jest oan dostepna

mozesz zrobic cos takiego:
ZaladowanyInterfejs.cast(zaladowanaklasa.newInstance());
no ale to zwraca typ T, wiec musialbys na cos rzutowac, a znowu nie masz na co
ogolnie to musialbys znac albo ten intefejs, albo jego metody, i wykonywac je rozniez porpzez refleksje (typ Method itp)

0

Trochę dziwne to jest, ale należy sobie przygotować takie coś jak fabryka obiektów. Będzie ona na podstawie zadanego interfejsu i klasy implementującej produkować obiekty.
Co zaś tyczy sie samego rzutowania:

Class zaladowanyInterface = Class.forName("moj.interf");
Class zaladowanaKlasa = Class.forName("moj.klas");
Object o = zaladowanyInterface.newInstance();
o = zaladowanyInterface.cast(o);

I oczywiście to nie zadziała ponieważ nie znasz nazwy interfejsu. Bez znajomości interfejsów nie można ich w praktyce używać. Można co prawda kombinować z refleksją, ale musisz wtedy w interfejsach używać jakiś zasad nazewnictwa metod i pól.

Zastanów się jeszcze czy rozwiązanie jest prawidłowe na poziomie pomysłu.

0

We właściwym projekcie interfejs będzie znany. Jadnak chciałem zrobić takie api co pozwoli że no. umieszcze w jednym folderze interfejs, w innym klasy po interfejsie. Następnie ma nastąpić załadowanie wszystkiego do takiego stanu bym mógł korzystać z załadowanych klas za pomocą załadowanego interfejsu. Nie przeczę że sie da. :-) Ale takie rozwiązanie mnie interesuje

0

to może java bean... ale tam tez trzeba znać interfejsy. Spróbuj zrobić tak:

  • wypisz wszystkie potrzebne interfejsy, nawet niech będą to zaślepki
  • stwórz je i skompiluj
  • do każdego napisz konfigurowalna za pomocą javabean fabryki.

Innej metody nie widzę. Generalnie interfejsy są do tego, żeby móc pisać soft bez potrzeby znajomości jak są zaimplementowane jego poszczególne części. Programowanie bez wiedzy jakie interfejsy należy wykorzystać jest skazane na zagładę.

0

Zawsze lubiłem hardcore :-)

0
cj_tomekk napisał(a)

We właściwym projekcie interfejs będzie znany. Jadnak chciałem zrobić takie api co pozwoli że no. umieszcze w jednym folderze interfejs, w innym klasy po interfejsie. Następnie ma nastąpić załadowanie wszystkiego do takiego stanu bym mógł korzystać z załadowanych klas za pomocą załadowanego interfejsu. Nie przeczę że sie da. :-) Ale takie rozwiązanie mnie interesuje

kolego jak juz ktoś powyżej napisał Fabryka obiektów to jest dokładnie to o co ci chodzi .....Factory Object
ponizej jest przykładowa klasa. Cmd to jest interfejs który implemetuja wszystkie klasy poniezej. w metodzie cmd(name) przrekazujesz jakis string po którym ma rozpozawac klasy nie wiem czy to nazwa czy cokolwiek. Metoda ta jak zauwazysz zwraca interfejs Cmd czyli moze to byc którakolwiek klasa implemetująca go bo on pozwoli ci wywołac na sobei metody tylko te które sam zawiera.

public class CmdFactory {

public Cmd cmd(String param) {



    if (param.equals("view")) {

        return new ViewCmdImpl();

    } else if (param.equals("list")) {

        return new ListCmdImpl();

    } else if (param.equals("delete")) {

        return new DeleteCmdImpl();

    } else if (param.equals("addform")) {

        return new AddFormCmdImpl();

    } else if (param.equals("add")) {

        return new AddCmdImpl();

    } else if (param.equals("updateform")){

        return new UpdateFormCmdImpl();

    } else if (param.equals("update")) {

        return new UpdateCmdImpl();

    } else {

        return new ErrorCmdImpl();
    }

}

}

no i gdzies tam tworzysz dalej
tworzysz

CmdFactory factory=new CmdFactory();
Cmd InstanceClassImpl=factory.cmd("update");

i teraz
InstanceClassImpl bedzie obiektem typu UpdateCmdImpl

no i posługujesz sie teraz tylko interfejsem nikt na zewnatrz nie bedzie musiał wiediec jaka jest implemetcja klasy i która została wybrany tylko fabryka o tym wie

0

uuuuuu, ale brzydki kod..
a nie lepiej tak:

private static final string VIEW="view";
private static final string LIST="list";
private static final string DELETE="delete";
private static final string ADD="add";
private static final Map<String,Class<? extends Cmd>> map=new TreeMap<String,Class<? extends Cmd>>();
static{
map.put(VIEW,ViewCmdImpl.class);
map.put(LIST,ListCmdImpl.class);
map.put(DELETE,DeleteCmdImpl.class);
map.put(ADD,AddCmd
}
public void myMethod(Stringparam){
   map.get(param).instance();
}

pozdrawiam

0

jeśli chodzi o wygląd to nie przecze ze moj jest brzydki ale łatwiejszy do zrozumienia i co ważniejsze mniej pamięciożerny. ładnie nie zawsze jest super , twój kod jest trudny do zrozumienia a juz na pewno dla początkującego. w ogóle to robisz tak ze przy tworzeniu obiektu fabryki najpierw tworzysz z góry pola stringowe ...bedzie ich 500 to zrobisz 500 stringów a potem jesczze od razu musisz zbudowac mape czyli kolejna pamiec. jak juz cos to lepiej chyba tak by było bez przepisywania stringów

private static final Map<String,Class<? extends Cmd>> map=new HashMap<String,Class<? extends Cmd>>();
static{
map.put("view",ViewCmdImpl.class);
map.put("list",ListCmdImpl.class);
map.put("del",DeleteCmdImpl.class);
map.put("add",AddCmdImpl.class);
}

jesczze nie widziałem takiej implemetacji fabryki obiektów ale pewnie zadziała chociaz czy na pewno ten kod

public void myMethod(Stringparam){
map.get(param).instance();
}

zwróci instancje obiektu ?? jak juz cos to tak

public Cmd myMethod(String param) throws Exception{
   return map.get(param).newInstance();
}

no dziwne rozwiązanie no ale pewnie zadziała. no moze byc.. ale sie rowinąłem.

pozdrawiam :)

0

to tak na marginesie, ale ty tez tworzysz tyle samo stringow w pamieci ile eximus, przeciez java jak widzi literal typu "jakis napis" sama alokuje dla niego poamiec we wspolnym poolu stringow

poza tym kod eximusa jest bardzo czytelny i logiczny, moze nie dla poczatkujacego ale jednak mi sie wydaje ze jest on mimo wszystko potezniejszy, a jakby wypelniac mape z pliku konfig jakiegos (przy duzym projekcie) to wcale nie trzeba zmieniac kodu zrodlowego aby dodawac nowe implementacje interfejsu Cmd czy jaki tam jest

to tyle, ale mozna sie nie zgadzac ze mna, specem nie jestem :-)

0

@Ktos inny ma racje co do stringow oraz super pomysl z plikiem config! poza tym ma to tez inny cel, gdyz w momencie gdy uzyjesz param dwa lub wiecej razy 1)teoretyczne zajmesz wiecej pamieci (w praktyce java sobie z tym radzi) 2)utrudniasz sobie refaktoryzacje

co do tego, ze metoda nie zwraca obiektu - oczywiscie - przeciez jest void. Pisalem "z palca" aby przekazac idee.
to czy jest bardziej czytelne dla poczatkujacego czy nie, to kwestia sporna, gdyz przebrnac przez iles "if"'ow to nie lada sztuka a jedyne, co musi zrobumiec w moim kodzie to wildcard.
No i jeszcze jedno - czy osoba, ktora bawi sie juz w refleksje oby na pewno jest poczatkujaca?

pozdrawiam

0

Co to za porządki !!!??? Co to za public static final ???!!! khe??

Java 5 panowie się kłania :D enumy stosujemy !!!

public class EnumObjectFactory {

	public static Cmd getInstance(ObjectFactory of) {
		Cmd instance = null;
		switch (of) {
		case ADD:
			instance = new ADDCmd();
			break;
		case DELETE:
			instance = new DELETECmd();
			break;
		case LIST:
			instance = new LISTCmd();
			break;
		case VIEW:
			instance = new VIEWCmd();
			break;
		default:
			break;
		}
		return instance;
	}

}
interface Cmd {}
//pulbiczny enum
public enum ObjectFactory {
	VIEW,
	LIST,
	ADD,
	DELETE;
}

no...

co do samej idei to problem nadal rozbija się o ładowany dynamicznie interfejs. Trzeba by mieć jakiś rzeczywisty interfejs lub coś w rodzaju Mocka.

0

chce zobaczyc jak ze swoim switchem dodajesz dynamicznie interfejsy z pliku config....

pozdrawiam

0

hehehe switch + enum był za miast bloku if/else i public static final.

teraz wredniejsza wersja i troszkę bardziej skomplikowana, wymaga pliku konfiguracyjnego .properties:

public class ObjectFactory {

    private static PropertyUtil pu;

    /**
     * domyślna implementacja
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     */
    public static Cmd getCmd()
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Cmd) ( Class.forName( pu.get( "cmd.implementation" ) ).newInstance() );
    }

    /**
     * implementacja wskazana przez uzytkownika
     * @param key
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     */
    public static Cmd getCmd(String key)
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Cmd) ( Class.forName( pu.get( key ) ).newInstance() );
    }
}

Wystarczy podać klucz, a następnie z pliku konfiguracyjnego zostanie pobrana nazwa klasy i zwrócona jej instancja. Rozwiązanie jest o tyle skomplikowane, że wymusza użycie pliku zewnętrznego. Jako, że nie mogę użyć drugi raz metody, która przyjmuje String zatem muszę się decydować na konkretną implementację. No zostaje jeszcze zrobienie fabryki abstrakcyjnej:

public abstract class ObjectFactory {

    protected static PropertyUtil pu;

    /**
     * domyślna implementacja
     * 
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     */
    public static Cmd getCmd()
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Cmd) ( Class.forName( pu.get( "cmd.implementation" ) ).newInstance() );
    }

    /**
     * implementacja wskazana przez uzytkownika
     * 
     * @param key
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     */
    public abstract Cmd getCmd( String key )
        throws InstantiationException, IllegalAccessException, ClassNotFoundException;
}

class ObjectFactoryProp
    extends ObjectFactory {

    /**
     * implementacja wskazana przez uzytkownika
     * 
     * @param key
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     */
    public Cmd getCmd( String key )
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Cmd) ( Class.forName( pu.get( key ) ).newInstance() );
    }
}

class ObjectFactoryKey
    extends ObjectFactory {

    /**
     * implementacja wskazana przez uzytkownika
     * 
     * @param key
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     */
    public Cmd getCmd( String key )
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Cmd) ( Class.forName( key ).newInstance() );
    }
}

i dostarczenie dwóch różnych implementacji. Świetnie sprawdzi się z czymś w rodzaju Springa

0

o rany, a co to za porzadki??? ;-)
/**
* implementacja wskazana przez uzytkownika
* @param key
* @return
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
public static Cmd getCmd(String key)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return (Cmd) ( Class.forName( pu.get( key ) ).newInstance() );
}

0

Nooo... nawet dokumentację dałem ;)

a na sam key to akurat dobrze bo Properties nie obsługuje enumów :)

0

hehe - i jednak musiales uzyc refleksji :P
enumy niestety na nic sie tu przydadza, ale wspolnie calkiem ladna fabryke opracowalismy :)

pozdrawiam

0

Przyszedł mi jeszcze jeden pomysł do głowy. Mianowicie użycie w fabryce generatora ByteCodu. Istnieja odpowiednie frameworki do takich manewrów. Można zatem użyć któregoś z nich i generować javowego asm.
Można jeszcze pokombinować z dynamicznym kompilowaniem. Robiłem kiedyś coś takiego, że na podstawie kodu konfiguracyjnego i szablonu generowałem plik .java i następnie kompilowałem go do .class. Pomysł był dziwny, ale całkiem nieźle się sprawdzał. Hm... ale fabryczka jest jeszcze do udoskonalenia by za pomocą JavaBean działała tak jak w Springu.

0

w naszym prjekcie do tego wykorzystujemy velocity + kompilator javy (dla pelnych klas) a jak trzeba cos malego na szybko pod reka skompilowac lub jakies wyrazenie obliczyc to korzystamy z Janino - taki maly ewaluator, fajnie dziala
jeszcze mozna podlaczyc bean shell jako jara i ma sie tez jakis tam interpreter
opcji jest wiele
pozdro

0

Jexl tez moze sie przydac

pozdrawiam

1 użytkowników online, w tym zalogowanych: 0, gości: 1