# Neue Instanz/Kopie einer unbekannten Klasse



## mabuhay (26. Okt 2010)

Hallo

Ich hoffe der Titel ist wenigstens ein bisschen aussagekräftig 
Also, ich habe folgende Situation:
Ich habe eine Server/Client Bibliothek. Der Server kann mehrere Verbindungen entgegennehmen und ankommende Daten verarbeiten. Jede Verbindung beinhaltet einen Incoming- und einen Outgoing-Processor wo die Daten verarbeitet/aufbereitet werden.

Für den Incoming- und Outgoing-Processor hab ich nun eine Abstrakte Klasse welche einige benötigte Methoden implementiert und auch einige abstrakte Methoden. Also z.B.:

```
public abstract class IncomingProcessor {
 public abstract read(InputStream in);
 public byte[] objectToByteArray(Object o) {
  ...
 }
}
```
Ich will nun die Möglichkeit haben, eine eigene Klasse zu erstellen (welche IncomingProcessor erweitert) und somit das Lesen der Daten mit der read()-Methode individuell zu gestalten.

Mein Problem ist nun, dass im Server bei jeder eingehenden Verbindung eine neue Instanz meiner individuell erstellten Klasse (welche IncomingProcessor erweitert) erstellt werden muss, da zum Beispiel die Information der Verbindung sich jedes mal ändert oder der IncomingProcessor auf Daten warten muss und die anderen Verbindungen nicht Blockieren sollte.

Dazu hab ich mir schon ein wenig das zeugs mit ClassLoader angeschaut. Ich kenn mich da nicht aus, aber es sieht so aus wie wenn dies ziehmlich kompliziert werden könnte.
Ein weiterer Ansatz ist irgendwie sowas:

```
Class<? extends IncomingProcessor> c = incoming.getClass();
IndividualIncomingProcessor in = c.newInstance();
```
Aber da meine Bibliothek ja nur die Abstrakte Klasse IncomingProcessor kennt und nicht die welche ich individuell erstellt habe gibt es da eine InstantiationException.


Kann mir jemand weiterhelfen oder hat Tipps? Sollte ich es am besten mit ClassLoader machen?

mfg


----------



## mfernau (26. Okt 2010)

Ich bin mir nicht sicher ob ich Deine Frage richtig verstanden habe. Es geht hier also um ein komplettes Projekt welches Du selbst entwickelst - ja? Also die ganze API (und damit auch der Teil wo ein Objekt von einer Klasse, welche IncomingProcessor erweitert, erstellt werden soll) liegt in Deinen Händen.
Wenn dem so ist, dann wäre wohl eine Factory der richtige Ansatz. Du musst also Deiner Server-API eine Factory zur Verfügung stellen, die genau die Objekte erstellt die es benötigt und die Du dort haben willst.
Eine Factory ist also eine Schnittstelle die durch deine Server-API zur Verfügung gestellt werden muss. Dort gibt es eine Methode "createIncomingProcessor", welche ein Objekt vom Typ IncomingProcessor zurück liefert:

```
interface IncomingProcessorFactory {
   public IncomingProcessor createIncomingProcessor();
}
```

Nun musst Du eine Implementation dieses Interfaces schreiben, in der Du mit dieser Methode Dein bestimmtes Objekt erzeugst, welches IncomingProcessor ableitet:

```
class IncomingProcessorFactoryImple implements IncomingProcessorFactory {
   public IncomingProcessor createIncomingProcessor() {
      // schlaue Sachen...
      return ...
   }
}
```

Deine Server-API muss Dir die Möglichkeit bieten irgendwie ein Objekt vom Typ IncomingProcessorFactory zu setzen, welches Dein Server dann dazu verwendet Objekte vom Typ IncomingProcessor zu erzeugen. Dadurch muss Dein Server nicht wissen welche Objekte tatsächlich dahinter stecken, sondern benutzt einfach Deine Factory-Klasse welche das tut, was Du möchtest.

Schau Dir dazu mal das "Factory Method Pattern" an.

HTH,
Martin


----------



## mabuhay (26. Okt 2010)

Hallo

Ja ich denke du hast es richtig verstanden 

Also sozusagen dass die individuell erstellte Klasse (welche IncomingProcessor erweitert) eine neue Instanz von sich erstellt und zurück gibt, z.B. einfach:


```
public abstract class IncomingProcessorFactory {
   protected String verbindungsinfo = null;
   public abstract IncomingProcessor createIncomingProcessor();
}
```


```
class IncomingProcessorFactoryImple implements IncomingProcessorFactory {

   public IncomingProcessor createIncomingProcessor(String verbindungsinfo) {
      IncomingProcessorFactoryImple ipf = new IncomingProcessorFactoryImple();
      ipf.verbindungsinfo = verbindungsinfo;
      return ipf;
   }

}
```

Seh ich das richtig? werde damit mal ein wenig experimentieren...

mfg


----------



## mfernau (26. Okt 2010)

Naja - eigentlich ist die Factory-Klasse nochmal eine eigenständige Klasse.

Für den Factory-Ansatz brauchst Du zwei neue Dinge.
1. Das Interface (in diesem Zusammenhang besser als eine abstrakte Klasse) mit dieser einen Methode
2. Eine implementierende Klasse

Dann erzeugst Du ein Objekt von der implementierenden Klasse. Dieses Objekt übergibst Du Deinem Server. Dein Server benutzt das Objekt um nach bedarf neue Instanzen von IncomingProcessor zu erzeugen.

Dein Ansatz würde zwar ebenfalls funktionieren - macht die Sache aber nicht ganz logisch. Denn Du brauchst in Deinem Fall ja schon eine Instanz von einer Klasse die IncomingProcessor erweitert hat um wiederum neue Instanzen seiner selbst zu erzeugen. Das ist nicht ganz der Sinn dahinter. Auch wenn das Ergebnis dasselbe wäre - das Factory-Pattern sieht das etwas anders vor 

Schau mal hier: Factory Method Pattern in Java (oder googel nach Factory Method Pattern)


----------



## mabuhay (27. Okt 2010)

Vielen Dank schonmal für deine Antworten. Ich komm da aber an einem Punkt nicht weiter:

Der Server und Client sind in einer Bibliothek. Ich mache nun in einem neuen Projekt eine Klasse A welche IncomingProcessorFactory erweitert, damit ich die read-Methode etc selber definieren kann.
Diese Klasse A muss ich ja jetzt irgendwie dem Server übergeben, dass der dann nach bedarf neue Instanzen erstellen kann. Du schreibst ja auch "Dieses Objekt übergibst Du Deinem Server", aber um das Objekt zu übergeben muss ich ja schon mal eine Instanz erzeugen oder?
Also z.B. mal als ganz einfaches Beispiel:

Dies ist in der Server/Client Bibliothek:

```
public abstract class IncomingProcessorFactory {
   public abstract IncomingProcessor createIncomingProcessor();
}
```

Im neuen Projekt erstelle ich eine Klasse, von welcher ich will dass der Server sie verwendet:

```
class A implements IncomingProcessorFactory {
 
   public A createIncomingProcessor() {
      A newA = new A();
      return newA;
   }

   public void read() {
      //...
   }
 
}
```

Der Server ruft nun bei jeder neuen Verbindung createIncomingProcessor() auf. Damit der Server aber überhaupt die Klasse des neuen Projekts verwenden kann muss dem Server ja newA übergeben werden:

```
public class Server {
    IncomingProcessorFactory ipf = null;
    public Server(IncomingProcessorFactory ipf) {
        this.ipf = ipf
    }

    public void run() {
        //...
        
        //Neue Verbindung
        IncomingProcessorFactory newIncoming = ipf.createIncomingProcessor();
    }
}
```

Also muss ich dort wo ich den Server erstelle, eine Instanz der Klasse A erstellen um die dann dem Server zu übergeben:

```
public void main() {
    A newA = new A();
    Server s = new Server(newA);
}
```

Ich verstehe dass ich dann die Klasse newA in der main-Methode habe, diese aber nicht verwenden kann/sollte da davon ja sowieso bei jeder Verbindung neue Instanzen erstellt werden.

Ich habe noch versucht die createIncomingProcessor()-Methode static zu machen, bei der BorderFactory zum Beispiel ist es ja auch so, aber dann bräuchte mein Server ja auch irgendwie den Klassennamen, und ausserdem geht static nicht in einem Interface...

Nun weiss ich nicht genau was ich falsch verstehe/sehe. Ich hab schon ein wenig recherchiert, aber hat mir noch keine Klarheit verschafft 

mfg


----------



## SlaterB (27. Okt 2010)

> A newA = new A();

schreibt man normalerweise nicht, wenn die Klasse A bekannt wäre bräuchte man überhaupt keine Factory,
(edit: siehe auch dein Titel: unbekannte Klasse)
und dass die Klasse sich selber erzeugt ist auch nicht gerade guter Stil, eine AutoFabrik erstellt ja auch Autos, nicht wieder AutoFabriken

das Objekt der Factory-Klasse kommt normalerweise von irgendwo anders her, z.B. hattest du am Anfang InputStream, objectToByteArray() usw.,
eine Alternative ist 
> Class.forName(String klassenname).newInstance()

dieses Factory-Objekt einer eher unbekannten Factory-Klasse auf das (bekannte!) Factory-Interface casten, dann kann die Factory-Methode verwendet werden


----------



## mfernau (27. Okt 2010)

Erstmal vorne weg:
1. Du verwechselst abstrakte Klassen mit Interfaces. Seit wann kann man abstrakte Klassen "implementieren"? Du tust es aber in deinem Zweiten Codeschnipsel.
2. Verwende für das Factory-Pattern Interfaces als Factory-Grundlage und implementiere diese dann in Deiner implementierenden Klasse.

So - und nun sehe ich, dass Du definitiv noch Verständnisprobleme bei diesem Thema hast. Ich hole nochmal aus:

Was Du schon mal richtig verstanden hast ist, dass Dein Server eine Instanz der Factory braucht.
Um mal kurz eine Übersicht zu erzeugen, welche Klassen/Interfaces wo liegen:
Package Server:
- Klasse _Server_ (von Dir angegeben)
- Abstrakte Klasse _IncomingProcessor_
- Interface _IncomingProcessorFactory_ (Für das Factory-Pattern)

So sieht das *Interface* _IncomingProcessorFactory_ aus:

```
public interface IncomingProcessorFactory {
   public IncomingProcessor createIncomingProcessor();
}
```

Und so sieht Deine abstrakte Klasse _IncomingProcessor_ aus (vom ersten Post von Dir)

```
public abstract class IncomingProcessor {
 public abstract read(InputStream in);
 public byte[] objectToByteArray(Object o) {
  ...
 }
}
```

So, wenn ich Dich nun richtig verstanden habe, dann erstellst Du Dir nun ein neues Projekt in Deiner IDE, welche Deine Server-Bibliothek verwendet. Das ist schon mal gut.
Eine Übersicht deines neuen Projekts:
- Klasse _MeinIncomingProcessor_
- Klasse _MeinIncomingProcessorFactory_

Sehen wir uns die Klassen mal im einzelnen grob an. Hier _MeinIncomingProcessor_:

```
public class MeinIncomingProcessor extends IncomingProcessor {
   public void read(InputStream in) {
      // muss implementiert werden, da sie abstrakt in Deiner Server-Bib ist
      // schlaue Sachen... 
   }
   // evtl andere Dinge ...
}
```

Und Dein Server soll für die Verbindung ja eine Instanz von MeinIncomingProcessor verwenden um den eingehenden Datenstrom zu verarbeiten. Eingangs war Deine Frage, wie Du dem Server klar machen sollst, dass er nun für eingehende Verbindungen eine Instanz von MeinIncomingProcessor erzeugen soll. Was ein Glück - wir benutzen ja hier das Factory-Pattern ;-) Der Server muss gar nicht wissen was er instantiieren soll - Du erledigst das für ihn. Nämlich mit der _MeinIncomingProcessorFactory_:


```
public class MeinIncomingProcessorFactory implements IncomingProcessorFactory {
   public IncomingProcessor createIncomingProcessor() {
      IncomingProcessor meinProcessor = new MeinIncomingProcessor();
      return meinProcessor;
   }
}
```

Dem Server übergibst Du nun einfach eine Instanz dieser _MeinIncomingProcessorFactory_:

```
MeinIncomingProcessorFactory factory = new MeinIncomingProcessorFactory();
Server s = new Server(factory);
```

Jedes mal wenn Dein Server eine Instanz von _IncomingProcessor_ benötigt, wird er die Factory-Methode _createIncomingProcessor()_ benutzen. Und weil Du diese Factory in Deinem Projekt so geschrieben hast, wird sie ein Objekt vom Typ _MeinIncomingProcessor_ liefern. Was der Server nicht weiss und auch nicht wissen muss. Denn ihm reicht es ja dass er weiss, dass es ein _IncomingProcessor_ ist.

Das Factory-Design-Pattern bietet Dir die Möglichkeit Deinem Server einen Objekt-Generator in die Hand zu geben, der die Art von Objekte erzeugt, die er für seine Aufgabe benötigt. Ohne das der Server selbst weiss aus welchen konkreten Klassen er Objekte instantiieren soll, bekommt er durch deine FactoryImplementierung für seinen Bedarf das richtige Objekt.
Die Klasse _MeinIncomingProcessorFactory_ könnte in einem dritten Projekt von Dir z.B. anders aussehen und andere _IncomingProcessor_ Objekte liefern. Dafür musst Du den Server aber nicht umschreiben. Dieser bedient sich einfach der Schablonen-Technik des Factory-Design-Patterns und bekommt das Objekt, welches Du für seine Zwecke als richtig erachtest.


----------



## mabuhay (28. Okt 2010)

Viiiielen Dank SlaterB und vorallem mfernau für die ausführliche Beschreibung :toll:
Jetzt wird zwar auch eine Instanz der Factory erstellt und muss dem Server übergeben werden, aber die hat ja nur die createXYZ-Klasse und kann somit nicht zu verwirrung führen, wie ich das vorher befürchtet habe 

@SlaterB: Ja stimmt, die ProcessFactory muss natürlich ein Prozess-Objekt zurückgeben, analog zur Autofarbrik welche Autos produziert.

Und sorry für das interface/abstrakt durcheinander, kam vom Copy-Paste.

mfg und Danke nochmals, wieder was nützliches gelernt


----------

