Typy generyczne. Jak przechować typ i utworzyć nowy obiekt danego typu?

0
package mode;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import presenter.BasicPresenter;
import presenter.IPresenter;
import view.BasicView;
import view.IView;

public class ModeCreator 
<
	TPresenter extends BasicPresenter<ITView>, 
	TView extends BasicView<ITPresenter>, 
	ITPresenter extends IPresenter, 
	ITView extends IView
>
{
	private Type _presenterType; //nie wiem czy Type to jest typ który przechowuje typ
	private Type _viewType;
	
	public ModeCreator(){
		_presenterType = //i tutaj chciałbym tak żeby ta zmienna przechowywała TPresenter (cos w stylu typeof(TPresenter);)
	}
}

Jaki typ zmiennej może przechować typ zmienej i jak go tam "wsadzić"? - TYPE?
Jak jak stworzyć obiekt typu TPresenter?

0

Nie wiem co chcesz osiągnąć, ale prezentuję odpowiedź na pytanie.

Najpierw zachowaj klasę:

Class<T> klass = object.getClass()

lub:

Class<T> klass = Klasa.class

Potem stwórz obiekt:

klass.newInstance();

lub:

klass.getConstructor(...).newInstance(...);
0
BasicPresenter<ITView> presenter;
BasicView<ITPresenter> view;

Jak z tego stworzyć nowe obiekty? - bo new BasicView<ITPresenter>(); to nie działa

0

Napisz konkretnie co chcesz osiągnąć bo na pierwszy rzut oka to jest klasyczny temat z serii "Mam do zrobienia coś prostego, ale wymysliłem tak skomplikowane rozwiązanie że język nie pozwala mi go zrealizować". Napisz co chcesz osiągnąć bo niestety na 95% twój pomysł na osiągnięcie tego jest po prostu zły.

0

Chce stworzyć obiekt typu np. BasicPresenter<ITView>. Normalnie bym napisał:

BasicPresenter<ITView> v = new BasicPresenter<ITView>();

ale tak nie działa...

0

Nie o to pytam. Pytam o cały problem. To o co pytasz teraz, tzn tworzenie obiektu typu generycznego w runtime, to jest już cześć twojego (zapewne błędnego) pomysłu na rozwiązanie jakiegoś problemu. Można to zrobić przez newInstance na obiekcie Class, niemniej to rzadko kiedy jest sensownym pomysłem...

Analogia:
Chcesz napełnić wodą basen przed domem. Wpadłeś na genialny plan żeby nabierać do czegoś wody z kranu i przelewać do basenu. Znalazłeś w domu sitko i próbujesz swojego pomysłu, ale woda z sitka ucieka zanim dobiegniesz do basenu :(
Przychodzisz na forum i pytasz W jaki sposób mogę nabrać wody za pomocą sitka? zamiast zapytać Jak mogę napełnić basen wodą?...

0

To co chce napisać jest powiązane z modelem MVP. Otóż klasa ModeCreator ma tworzyć pary presenter + widok (Mode).
I teraz w zależności od otrzymanych typów chce utworzyć obiekt prezentera i widoku i potem w metodzie je zwrócić.

Tak deklaruje klasy:

public abstract class BasicPresenter <TIView extends IView>{}
public abstract class BasicView <TIPresenter extends IPresenter>{}

Ps. Zapomniałem że są abstrakcyjne ale w przykładzie z C# to działało:

 
Type _modelType = typeof(TModel);
Type _viewType = typeof(TView);
BasicModel<TIView> model = (BasicModel<TIView>)Activator.CreateInstance(this._modelType);
BasicView<TIModel> view = (BasicView<TIModel>)Activator.CreateInstance(this._viewType);

A tak tworze nowy obiekt ModeCreator

ModeCreator _mode = new ModeCreator<LoginPanelPresenter, LoginPanelView, ILoginPanelPresenter, ILoginPanelView>();

Pierwszy raz spotykam typy generyczne i trochę mnie "niszczą"...

0

No dobra, ale po co ci tu te wszystkie generyki? Serio. Na przykład
public abstract class BasicPresenter <TIView extends IView>{} albo public abstract class BasicView <TIPresenter extends IPresenter>{}
Jaki jest sens robienia z tych klas generycznych? Czy ona rzeczywiście w jakiś sposób zależą od "typu" widoku czy prezentera? Czy nie wystarczy że po prostu będziesz tam miał pole typu bazowego a resztę załatwi polimorfizm / strategia?

Abstrahuje tu jednocześnie od tego że dla mnie te prezentery i widoki to powinny być jakieś singletonowe serwisy...

0

Nie podawałem ciała tych klas bo to nie jest teraz istotne. W np. klasie BasicPresenter musi być obiekt TIView + różne metody wspólne dla wszystkich prezenterów i analogicznie z widokiem. Więc wydaje mi się że zastosowanie abstrakcyjnych klas jest jak najbardziej ok.

0

Abstrakcyjnych może i tak ale niekoniecznie generycznych...

interface IView{
    void metoda1();
}

class ViewOne implements IView{
    void metoda1(){
        //cośtam
    }
}

class ViewTwo implements IView{
    void metoda1(){
        //cośtam innego
    }
}

class BasicPresenter{
    private final IView view;
    BasicPresenter(IView view){
        this.view = view.
    }

    public void metoda(){
        view.metoda1();
    }
}

I voila. Nie ma żadnych generyków a mimo to wszystko śmiga. Ponawiam pytanie: co w tych klasach u ciebie zależy od typu parametrów?

0

Widok:

  1. Każdy widok dziedziczy po BasicView i implementuje SWÓJ interfejs który dziedziczy po IView.
  2. Każdy widok posiada osobny prezenter który zawiera odpowiednie metody do jego obsługi.

Prezenter:

  1. Każdy widok dziedziczy po BasicPrezenter i implementuje SWÓJ interfejs który dziedziczy po IPrezenter.
  2. Każdy prezenter jest dla osobnego widoku.

I teraz jeśli bym nie użył generyków i np. ustawił wszedzie IView to nie mam możliwości wywołać metody która zawarta jest w konkretnym interfejsie.

W IView będą tylko i wyłącznie metody potrzebne do "instalacji" widoku + pare innych a samym "instalowaniem będzie się zajmował Dispatcher który w ogóle będzie miał listę Mode'ow (para prezenter + vidok) i w zależności od potrzeb będzie je aktualizował.

Domyślam się że chyba da się to napisać bez tego (bo coś mi tam świta) ale "prościej" (optymalnie) będzie mi to napisać w ten sposób.

0
shimizu napisał(a):
package mode;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import presenter.BasicPresenter;
import presenter.IPresenter;
import view.BasicView;
import view.IView;

public class ModeCreator 
<
	TPresenter extends BasicPresenter<ITView>, 
	TView extends BasicView<ITPresenter>, 
	ITPresenter extends IPresenter, 
	ITView extends IView
>
{
	private Type _presenterType; //nie wiem czy Type to jest typ który przechowuje typ
	private Type _viewType;
	
	public ModeCreator(){
		_presenterType = //i tutaj chciałbym tak żeby ta zmienna przechowywała TPresenter (cos w stylu typeof(TPresenter);)
	}
}

Jaki typ zmiennej może przechować typ zmienej i jak go tam "wsadzić"? - TYPE?
Jak jak stworzyć obiekt typu TPresenter?

public class ModeCreator 
<
	TPresenter extends BasicPresenter<ITView>, 
	TView extends BasicView<ITPresenter>, 
	ITPresenter extends IPresenter, 
	ITView extends IView
>
{
	private Class<? extends BasicPresenter<ITView>> _presenterType;
	private Class<? extends BasicView<ITPresenter>> _viewType;
	
	public ModeCreator(Class<? extends BasicPresenter<ITView>> _presenterType _presenterType) {
		this._presenterType = _presenterType;
	}
}

Mogłem coś zwalić, bo dawno w Javie nie klepałem. Tylko Scala teraz :P

0
public ModeCreator() throws InstantiationException, IllegalAccessException{
	TPresenter presenter = null;
	Class _presenterType = presenter.getClass();
		
	BasicPresenter<ITView> a = (BasicPresenter<ITView>)_presenterType.newInstance();
	}
0

Erm, ale jak wywołasz metodę na nullu to dostaniesz NullPointerException.

Klasę musisz podać z zewnątrz tak jak to pokazałem post wyżej.

0

Czyli nie da się tak że jak tworze sobie nowy obiekt ModeCreator bez przesyłania rzeczy w konstruktorze który stworzy w środku taki prezenter i taki widok?

Bo chodzi o to że typy ich i tak przekazuje pomiędzy <...>.

1

Nie da się. Ale możesz przecież przesłać obiekt typu Class. Co to za problem?

Jeżeli w C# masz klasę:

class A<B> {
  B zróbB() {
    return new B();
  }
}

i tworzysz ją w ten sposób:
new A<B>();
To w Javie będziesz musiał zrobić coś takiego:

class A<B> {
  Class<? extends B> klass;
  public A(Class<? extends B> klass) {
    this.klass = klass;
  }
  B zróbB() {
    return klass.newInstance();
  }
}

i tworzysz ją w ten sposób:
new A<B>(B.class);

Wygląda paskudnie, bo refleksja jest paskudna i powinieneś ją zastąpić kompozycją jak zasugerował Shalom.

Bo chodzi o to że typy ich i tak przekazuje pomiędzy <...>.

W Javie jest type erasure: https://docs.oracle.com/javase/tutorial/java/generics/erasure.html

0
public class ModeCreator 
<
	TPresenter extends BasicPresenter<ITView>, 
	TView extends BasicView<ITPresenter>, 
	ITPresenter extends IPresenter, 
	ITView extends IView
>
{
	 private Class<? extends BasicPresenter<ITView>> _presenterType;
	 private Class<? extends BasicView<ITPresenter>> _viewType;
	
	 public ModeCreator(Class<? extends BasicPresenter<ITView>> _presenterType, Class<? extends BasicView<ITPresenter>> _viewType) {
	        this._presenterType = _presenterType;
	        this._viewType = _viewType;
	 }
	
	public Mode CreateMode() throws InstantiationException, IllegalAccessException{
		BasicPresenter<ITView> presenter = _presenterType.newInstance(); // ----------1
		BasicView<ITPresenter> view = _viewType.newInstance(); // ---------------------2
		return new Mode(presenter,view); //blad ale to potem naprawie
	}
}

a obiekt ModeCreator będę tworzył:

_modes[(int)ModeType.LoginPanel.ordinal()] = 
new ModeCreator<LoginPanelPresenter, LoginPanelView, ILoginPanelPresenter, ILoginPanelView>(LoginPanelPresenter.class, LoginPanelView.class);

To chyba w moim przypadku tak to będzie. Tylko czy czasem ILoginPanelPresenter i ILoginPanelView i nie powinienm przekazać tak jak LoginPanelPresenter i LoginPanelView przez konstruktor i potem też wyciągać typ i go wsadzać tam ( 1, 2 )...?

0

Nie żebym narzekał, ale jak widzę

public class ModeCreator 
<
    TPresenter extends BasicPresenter<ITView>, 
    TView extends BasicView<ITPresenter>, 
    ITPresenter extends IPresenter, 
    ITView extends IView
>
{
     private Class<? extends BasicPresenter<ITView>> _presenterType;
     private Class<? extends BasicView<ITPresenter>> _viewType;
 

To jedyne co mi przychodzi do głowy: I had a problem and I tried to use Java to solve it. Now I have ProblemFactory.
Ja tam nie wiem, może piszesz ui-core dla jakiegoś wielkiego projektu, ale generalnie wygląda to na over-engineering i mocne przekombinowanie. Bo ta twoja klasa wygląda mi na jakis taki GodObject albo MotherOfAllClasses.
Nie ma bardzo rozumiem ideę tej magicznej klasy do tworzenia tych twoich obiektów. Czemu nie używasz tu IoC? Przecież te klasy i tak muszą być gdzieś zadeklarowane, więc czemu nie zrobisz z nich po prostu @Service czy @Named a potem odpowiednio powstrzykujesz?

0
Wibowit napisał(a):

Jeżeli w C# masz klasę:
class A<B> {
B zróbB() {
return new B();
}
}

> i tworzysz ją w ten sposób:
> `new A<B>();`


@Wibowit: nie pisalem baaardzo dawno w C#, jak jeszcze nie bylo generykow, wiec moze odpowiedz - w jaki sposob zagwarantowane jest, ze B ma konstruktor domyslny/bezargumentowy? Czy np. w miejscu uzycia jest to sprawdzane, tzn. widzac new A<B>() kompilator sprawdza czy new B() jest mozliwe?
0

Ja w C# nie napisałem niczego co by działało :]
Kod miał być tylko poglądowy.

Jakiś @somekind mógłby napisać poprawny kod (ale chyba nie trzeba w sumie).

0

@Wibowit, @the real mućka, do constraintów w C# służy where:

class A<B>
    where B : new()
{
    B zróbB()
    {
        return new B();
    }
}

@shimizu, napisałem już w życiu kilka implementacji MVP w C#, i w żadnej czegoś takiego nie miałem. Generalnie PresenterBase posiadał pole typu TView (który był IViewBase), a konkretne implementacjie widoków miały pola typu PresenterBase<TView>, (gdzie TView był IViewBase) i to właściwie koniec generyków. Po co Ci tego aż tyle?

0

@somekind, @Wibowit: znalazlem takie cos: https://msdn.microsoft.com/en-us/library/d5x73970.aspx
Z tego wynika ze te constrainty sa dosc ograniczone, np. mozna wymagac konstruktora bez parametrow, ale juz z jakims konkretnym parametrem nie mozna. Np. nie mozna wymagac konstruktora ktory bierze int oraz metody foo(string)? Nie jest to ograniczajace, starcza to? (Tak, zdaje sobie sprawe ze to i tak duzo elastyczniejsze rozwiazanie niz w Javie.)
W Scali nazywa sie takie cos zdaje sie 'structural typing' - mozna napisac metode ktora bierze jakis parametr ktory ma wymagana metode (choc podobno sie nie uzwa tego zbyt czesto, nie wiem nie uzywam Scali na codzien).

0

Structural typing ZTCP opiera się na refleksji i dzięki niej w czasie wykonania jest wyciągana odpowiednia metoda do wywołania. Stąd jest duży narzut, a co za tym idzie - mała popularność.

0

@the real mućka, metody możesz wymagać przez interfejs. Konstruktora innego niż bezparametrowy wymagać nie można. Na pewno jest to jakieś ograniczenie, ale jakoś nie przypominam sobie, żeby mi czegoś takiego brakowało kiedykolwiek.

0

@somekind: Ok, dzieki za odpowiedz.

somekind napisał(a):

metody możesz wymagać przez interfejs

Tak, ale structural typing pozwala na 'duck typing', tzn. jesli cos ma metode foo(int) to obojetnie czy to jest klasa A, B czy Duck - moze zostal przeslane do takiej metody i bedzie dzialac. W sumie na tej zasadzie dziala to ograniczenie new() - niewazne jaki typ ma klasa, jakie interfejsy implementuje; wazne, ze implementuje specjalna metode/bezparametrowy konstructor.
Ok, koniec offtopa z mojej strony.

0

No cóż, C# po prostu nie jest typowany w ten sposób. Ale takie zachowanie można z łatwością zaimplementować przy użyciu refleksji. :)

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