2010-05-18 19 views
6

Piszę (dobrze, uzupełniając) "rozszerzenie" Javy, które pomoże w programowaniu roli.
Tłumaczę mój kod na kod Java za pomocą javacc. Moje kompilatory dodają do każdej zadeklarowanej klasy jakiś kod. Oto przykład, aby być bardziej precyzyjne:Java: extending Klasa obiektu

MyClass extends String implements ObjectWithRoles { //implements... is added 
    /*Added by me */ 
    public setRole(...){...} 
    public ... 
    /*Ends of stuff added*/ 
    ...//myClass stuff 
} 

Dodaje Implements .. i metod niezbędnych do każdej pojedynczej klasy deklarowania. Całkiem szorstki, prawda?

Będzie lepiej, jeśli napiszę moje metody w jednej klasie i cała klasa rozszerzy to .. ale .. jeśli klasa już rozszerza inną klasę (tak jak przykład)?

Nie chcę tworzyć rodzaju opakowania, które zarządza rolami, ponieważ nie chcę, aby programista wiedział o wiele więcej niż Java, kilka nowych zastrzeżonych słów i ich wykorzystanie.

Mój pomysł polegał na przedłużeniu java.lang.Object .. ale nie można. (prawda?)
Inne pomysły?

Jestem tu nowy, ale śledzę tę stronę, więc dziękuję za przeczytanie i wszystkie odpowiedzi, jakie dajecie! (Przepraszam za angielski, jestem włoski)

+4

Nie można rozszerzyć 'String'. Jest to ostatnia klasa, nie można jej podklasować: http://java.sun.com/javase/6/docs/api/java/lang/String.html –

+2

"Mój pomysł polegał na przedłużeniu java.lang. Obiekt .. ale nie możesz. (Prawda?) " Hmm, powiedziałbym, że każda klasa, w której nie ma podklas rozszerzeń Obiekt domyślnie. –

+1

@James P. Myślę, że Fabio miał na myśli, że zastąpił obiekt swoją własną zaktualizowaną wersją. I to można zrobić, zrobić ogólną klasę bazową dla własnej aplikacji i rozszerzyć wszystko stamtąd. Ale nie chcesz dodawać, że rozszerza się automatycznie na wszystko :) – extraneon

Odpowiedz

6

Jeśli jest to tylko projekt "badawczy", w którym chcesz sprawdzić, jak takie rozszerzenie może działać, możesz podać własną implementację klasy Object. Wystarczy skopiować istniejącą implementację obiektu, dodać swoją metodę setRole itd. I podać -Xbootclasspath:.:/usr/lib/jvm/java-6-sun/jre/lib/rt.jar jako parametr polecenia java. (Będę szukał api-klas w . zanim zajrzysz w prawdziwe rt.jar.)

+0

Próbuję zaimplementować twoje rozwiązanie: dodanie pliku Object do katalogu (.) Java/lang/Object.java zmodyfikowane moimi metodami. Kompiluje (więc znajduje metody), ale kiedy próbuję wykonać, otrzymuję NoSuchMethodError. Użyłem opcji -Xbootclasspath i -classpath z tym samym wynikiem. (Javac działa nawet bez tego!) –

+0

powinieneś dodać Object.class, nie w katalogu '.', ale w katalogu'./Java/lang'. – aioobe

+0

Głupi angielski .. zrobiłem, że skopiowałem java/lang. Kompiluje, ale nie wykonuje. Przepraszam .. –

3
  • można przedłużyć Object - każda klasa rozszerza go.
  • wydaje się, że potrzebujesz czegoś takiego jak wiele dziedziczenia - nie ma czegoś takiego w Javie
  • jeśli chcesz dodać funkcjonalność, użyj kompozycji obiektu. Tj

    YourClass extends Whatever implements ObjectWithRoles { 
        private RoleHandler roleHandler; 
        public RoleHandler getRoleHandler() {..} // defined by the interface 
    } 
    

A potem wszystkie metody są umieszczane w RoleHandler

+0

Kiedy powiedziałem "przedłuża obiekt" myślałem, że stworzyłem super klasę obiektu, to nie był właściwy termin, przepraszam. W każdym razie twoja odpowiedź jest przydatna, sprawdzę, czy to rozwiązanie. Dziękuję Ci. Fabio F. –

+3

czekaj, myślę, że mówi o rozszerzeniu klasy Object, dodając funkcjonalność do WSZYSTKICH obiektów –

3

Należy rozważyć zastosowanie kompozycji zamiast dziedziczenia w celu rozwiązania tego problemu; w ten sposób możesz zapewnić funkcjonalność, której potrzebujesz, bez używania "jednego strzału" w dziedziczeniu.

Na przykład JDK udostępnia klasę PropertyChangeSupport, która może być używana do zarządzania PropertyChangeListener s oraz wyzwalaniem PropertyChangeEvent s. W sytuacjach, w których chcesz napisać klasę, która odpala PropertyChangeEvent s, możesz osadzić zmienną instancji PropertyChangeSupport i przekazać do niej wszystkie wywołania metod. Ten numer pozwala uniknąć dziedziczenia i oznacza, że ​​można uzupełnić istniejącą hierarchię klas o nową funkcjonalność.

public class MyClass extends MySuperClass { 
    private final PropertyChangeSupport support; 

    public MyClass() { 
    this.support = new PropertyChangeSupport(this); 
    } 

    public void addPropertyChangeListener(PropertyChangeListener l) { 
    support.addPropertyChangeListener(l); 
    } 

    protected void firePropertyChangeEvent() { 
    PropertyChangeEvent evt = new ... 
    support.firePropertyChangeEvent(evt); 
    } 
} 
1

Jeśli robisz to, co robisz, dziedziczenie prawdopodobnie nie jest właściwym idiomem. Możesz rozważyć wzorzec dekoratora, w którym możesz skonstruować klasę, która bierze za swój parametr inną klasę o mniejszej funkcjonalności, i dodaje do niej dodatkową funkcjonalność, delegując do istniejącej klasy dla funkcjonalności, która już istnieje. Jeśli implementacja jest wspólna dla wielu twoich dekoratorów, możesz rozważyć umieszczenie tej klasy w klasie, która może być współużytkowana i do której możesz oddelegować dla wszystkich dekoratorów. W zależności od tego, czego potrzebujesz, podwójna wysyłka lub odbicie mogą być odpowiednie w celu zrobienia podobnych, ale nie całkiem takich samych dekoratorów dla wielu różnych klas.

Ponadto, jak wskazano w komentarzach, String jest uznawany za "ostateczny" i dlatego nie może być przedłużony. Tak więc powinieneś naprawdę rozważyć rozwiązanie polegające na delegowaniu/dekorowaniu obiektów.Na przykład, możesz mieć jakiś obiekt, który owija łańcuch i zapewnia dostęp do łańcucha znaków przez getString() lub toString(), ale dodaje dodatkowe funkcje na górze klasy String.

Jeśli chcesz skojarzyć niektóre obiekty z dodatkowymi atrybutami, użyj numeru Map (np. HashMap).

+1

1) Nie ma czegoś takiego jak "pakiet na najwyższym poziomie". 2) Klasy o nazwie "Obiekt" są zdecydowanie * nie * automatycznie rozszerzane przez inne klasy w tym samym pakiecie. –

+1

Jestem w 100% pewien, że nigdy nie pracowałem w dowolnej JVM zgodnej z normami. –

+0

@Michael, nevermind, myślę, że mogłem pomylić z AS3 lub jakimś innym językiem z najwyższą super klasą z podobnym hackem. –

2

Jeśli mówisz o dodaniu roli do wszystkich twoich obiektów, rozważyłbym również rozwiązanie oparte na adnotacjach. Możesz opisywać swoje zajęcia za pomocą czegoś w stylu @Role ("Użytkownik"). W innej klasie możesz wyodrębnić tę wartość roli i użyć jej.

myślę, że trzeba adnotację retencję wykonawczego i można sprawdzić, czas pracy, czy adnotacja jest obecny przy użyciu odbicia i uzyskać adnotacji przy użyciu getAnnotation. Uważam, że byłoby to o wiele czystsze niż automatyczne rozszerzanie wszystkich zajęć.

Wierzę, że istnieją pewne ramy, które używają właśnie takiego rozwiązania, więc gdzieś powinien być przykładowy kod.

1

To, co naprawdę chcesz zrobić, to monkey patching, tj. Zmiana zachowania istniejących klas bez modyfikowania ich kodu.

Niestety, Java nie obsługuje tego, ani rzeczy takich jak mixins, które mogą być używane alternatywnie. Więc jeśli nie chcesz przejść na bardziej dynamiczny język jak Groovy, będziesz musiał żyć z mniej eleganckimi rozwiązaniami, takimi jak kompozycja.

+0

Nie koniecznie potrzebujesz dynamicznie wpisywanego języka, takiego jak Groovy lub Ruby, do patchowania lub miksowania małp - niektóre statyczne języki, na przykład Scala, również obsługują mixiny, i możesz zrobić coś, co wygląda jak łatanie małpki w Scali z " pimp my library "wzór. – Jesper