Planlos: Uebung Abstrakte Klassen mit abstrakten Parametern

Hallo Leute,

hab eine kleine Aufgabe, bei der ich nicht richtig weiter weiß.
PS: Ich weiß, es gehört sich nicht, in einem Forum solche Fragen (aus dem Studium) zu stellena, aber ich komme einfach nicht auf den  Trichter.

Also, ich habe eine abstrakte Klasse mit einer abstrakten Methode

public abstract class Printer{
  public abstract void print(Document doc);
}

Zwei weitere Klassen sind von Printer abgeleitet

public class LinePrinter extends Printer{
  public void print(Document doc);
}
pubic class Plotter extends Printer{
  public void print(Document doc);
}

Soweit, so gut!
Nur.....Der Methodenparameter "Document" soll selbst eine abstrakte Klasse sein und die beiden Klassen "Text" und "Drawing" sind davon abgeleitet.
Die Klasse LinePrinter soll in seiner Methode print(..) nur "Text" drucken und die Klasse Plotter soll in seiner Methode print(..) nur "Drawing" drucken können.

Wie mache ich das???? Keine Ahnung, wie man abstrakte Parameter abbildet.

Hoffe, ihr könnt mir zumindest einen Tipp geben.

Vielen Dankle und Grüßle!

  1. Hi!

    PS: Ich weiß, es gehört sich nicht, in einem Forum solche Fragen (aus dem Studium) zu stellen [...]

    Wurde das so konkret als Aufgabe gestellt oder ist das nur dein Lösungsversuch einer allgemein formulierten Aufgabe?

    Die Klasse LinePrinter soll in seiner Methode print(..) nur "Text" drucken und die Klasse Plotter soll in seiner Methode print(..) nur "Drawing" drucken können.
    Wie mache ich das???? Keine Ahnung, wie man abstrakte Parameter abbildet.

    Macht man das nicht genauso wie bei einem Interface oder einem konkreten Typ? Du willst aber nicht nur einen abstrakten Typ angeben, sondern mal diesen und mal jenen konkreten Typ übergeben, das aber einer mit allgemeinem Typ definierten Methode. Das geht meines Erachtens nicht, weil die konkreten Typen jeweils andere Methodensignaturen ergeben, die nicht mehr mit der abstrakten Methode übereinstimmen.

    Hoffe, ihr könnt mir zumindest einen Tipp geben.

    Ich denke, dass der jeweils gewünschte Typ übergeben wurde, kannst du nur zur Laufzeit mit einer konkreten Typprüfung testen.

    Lo!

  2. Servus,

    Generic types sollte dir einen guten Einstiegspunkt liefern.

    Gruss
    Patrick

    1. Hi!

      Generic types sollte dir einen guten Einstiegspunkt liefern.

      Inwiefern soll ihm das helfen? Ein Generic Type ist in seinem Szenario ähnlich der Verwendung eines abstrakten Typs, nur dass eben alle Typen und nicht nur von Document abgeleitete verwendet werden können. Er hat dann immer noch keine Einschränkung auf bestimmte Typen in den print-Methoden der abgeleiteten Klassen - im Gegenteil. Das Problem bleibt, dass die Methodensignaturen durch Einschränkungen auf andere/konkretere Typen nicht mehr die selben sind und damit nicht die abstrakte print-Methode treffen.

      Ich hatte das auch in Erwägung gezogen, aber mit C# habe ich nichts hinbekommen. Vielleicht kennt Java andere Möglichkeiten ... Das war jedenfalls meine (C#-)Idee:

      public abstract class Document { }
        public class Text : Document { } // der : ist das Äquivalent zu Javas extends
        public class Drawing : Document { }

      public abstract class Printer {
          public abstract void print<T>(T doc) where T : Document;
          // mit dem where kann man den generischen Typ einschränken
          // dürfte Javas Bounded Type Parameters entsprechen:
          // public abstract void print<T extends Document>(T doc);
        }

      public class LinePrinter : Printer {
          public override void print<T>(T doc) where T : Text { }
          // hier meckert der C#-Compiler, weil er die where-Einschränkung
          // generell aus der geerbten Methode übernimmt.
        }

      public class Plotter : Printer {
          public override void print<T>(T doc) where T : Drawing { }
        }

      Es geht auch nicht:

      public abstract class Printer {
          public abstract void print(Document doc);
        }

      public class LinePrinter : Printer {
          public override void print<T>(T doc) where T : Text { }
        }

      Der Compiler findet, die beiden print-Methoden überschreiben sich nicht. Auch in folgendem Versuch nicht (weder mit Text noch mit Document als Typ im where-Constraint - diesmal an der Klasse statt der print-Methode):

      public abstract class Printer {
          public abstract void print(Document doc);
        }

      public class LinePrinter<T> : Printer where T : Text {
          public override void print(T doc) { }
        }

      Lo!

      1. Servus,

        Ein Generic Type ist in seinem Szenario ähnlich der Verwendung eines abstrakten Typs, nur dass eben alle Typen und nicht nur von Document abgeleitete verwendet werden können. [...]

        Nein, da hast du etwas falsch verstanden und dementsprechend auch in allen Beispielen falsch angewandt. Nur die generische Klasse deklariert den generischen Typ, alle Implementation erweitern diese mittels konkreten Typings:

          
        public abstract class Document {}  
        public class Text extends Document {}  
          
        public abstract class Printer<T extends Document> {  
          
        	public abstract void print(T doc);  
        }  
          
        public class LinePrinter extends Printer<Text> {  
          
        	@Override  
        	public void print(Text doc) {  
          
        		// TODO Auto-generated method stub  
        	}  
        }  
        
        

        Gruss
        Patrick

        1. Hi!

          Ein Generic Type ist in seinem Szenario ähnlich der Verwendung eines abstrakten Typs, nur dass eben alle Typen und nicht nur von Document abgeleitete verwendet werden können. [...]
          Nein, da hast du etwas falsch verstanden und dementsprechend auch in allen Beispielen falsch angewandt.

          Du hast nur ein Stichwort hingeworfen. Es gibt eine ganze Menge unterschiedliche Arten der Anwendungen von generischen Typen, so dass die Chance, zu verstehen wie du dir die Lösung vorgestellt hat, nicht zwangsläufig sehr hoch ist.

          Nur die generische Klasse deklariert den generischen Typ, alle Implementation erweitern diese mittels konkreten Typings:

          Ok, so kann man es machen und es sieht erst einmal gut aus. Das compiliert auch in der C#-Variante. Die Lösung hat jedoch die Eigenschaft, dass man immer Printer<mit_konkretem_Document_Type> als Typangabe verwenden muss. Beispielsweise geht nicht, Printer<Document> als Typ und dann einen LinePrinter oder Plotter zu übergeben. Lediglich einen LaserPrinter (der von Printer<Document> abgeleitet ist und damit alle Arten Dokumente drucken kann/können muss) kann man zuweisen. Aber es geht auch sowas (C#):

          void foo<TDoc>(Printer<TDoc> p, TDoc doc) where TDoc: Document {
              p.print(doc);
            }

          Java-Syntax düfte diese sein:

          void foo<TDoc extends Document>(Printer<TDoc> p, TDoc doc) {
              p.print(doc);
            }

          Damit kann man foo(linePrinter, textDocument) oder foo(plotter, drawing) oder foo(laserPrinter, textDocument) aufrufen, also spezialisierte Drucker mit einem konkretem DokumentTyp oder konkrete allgemeine Drucker mit beliebigen Dokumenten.

          Diese Eigenschaft der Lösung bedingt also, dass zur Compile-Zeit bereits die konkret verwendeten Typen von Dokumenten und Drucker feststehen müssen.

          Lo!