Laden...

Wie implementiert man Klassen die zur Designzeit nicht bekannt sind?

Erstellt von userid4382 vor 16 Jahren Letzter Beitrag vor 16 Jahren 1.336 Views
U
userid4382 Themenstarter:in
239 Beiträge seit 2006
vor 16 Jahren
Wie implementiert man Klassen die zur Designzeit nicht bekannt sind?

Zur Zeit experimentiere ich immer noch mit WinForm-Controls, die zur Laufzeit generiert werden. Derweil ist es ein TableLayoutPanel, das zur Laufzeit mit PictureBoxen befüllt wird. Fährt man mit der Maus über dieses Grid, leuchten die entsprechenden "Zellen" auf und nehmen langsam wieder ihre ursprüngliche Farbe an, wenn man mit der Maus die Zelle verlässt. Dieser Fade-Effekt läuft in einem eigenen Thread, besser gesagt, einer pro PictureBox. Ich weiß das ist Spielerei, aber so lerne ich am besten. Bis hierhin klappt alles wunderbar.
Gestern abend kam mir dazu die Idee, dieses Panel mit den PictureBoxen in ein eigenes Control zu ändern (LED-Grid). Das ist aber Stoff für das übernächste Sub-Projekt. Als nächstes möchte ich die Funktionalität möglichst flexibel erweitern. Ich denke da an eine Art Plugin. Da ist also auf der einen Seite die Klasse, die mir das Grid zur Verfügung stellt. Idealerweise wird diese Klasse nicht mehr verändert. Auf der anderen Seite ist eine Klasse mit Plugins, die irgend etwas mit dem Grid anstellen. Das könnte z.B. eine Frequenzgang-Anzeige sein, eine Laufschrift, Tetris, Binär-Uhr, etc.
Nun stehe ich vor dem Problem, daß a) gerade dieses Plugin als eigener Thread laufen muß, aber b) die Grid-Klasse das Plugin nicht "sieht".
Weil ich euch nicht zumuten möchte, über 100 Zeilen Code zu lesen, habe ich dieses abstrakte Beispiel gepostet. Man beachte meinen Kommentar bei InvokeThreading.
Hat jemand eine Idee?

using System;
using System.Threading;

namespace ProxyTest
{
   class Program : IProxy
   {
      Functionality func;
      public Program()
      {
         func = new Functionality();
      }
      static void Main()
      {
         Program that = new Program();
         that.func.InvokeThreading();
      }
	  #region IProxy Members
      public void Plugin(object state)
      {
         func.DummyObject = "Hallo";
      }
	  #endregion
   }

   public interface IProxy
   {
      void Plugin(object state);
   }

   public class Functionality
   {
      private static string dummyTransporter = string.Empty;
      public string DummyObject
      {
         get { return dummyTransporter; }
         set { dummyTransporter = value; }
      }

      public void InvokeThreading()
      {
         // Das ist Mist. Die Klasse muß nicht Program heißen!         
         IProxy px = new Program();
         ThreadPool.QueueUserWorkItem(new WaitCallback(px.Plugin));
         while(DummyObject.Equals(string.Empty))
            ;
         DoWork();
      }

      private void DoWork()
      {
       // Simuliert die Durchführung einer Aufgabe:
         Console.WriteLine(dummyTransporter);
      }
   }
}
139 Beiträge seit 2006
vor 16 Jahren

System.Reflection

MSDN hat alles was du brauchst. Lese die Ctor's des Typen aus und erstelle ihn zur laufzeit. Google hat so einiges an Beispielen zu bieten.

Gruss Ari
Wer lesen kann ist klar im vorteil!
MSDN
Dein Feund in allen fragen

U
userid4382 Themenstarter:in
239 Beiträge seit 2006
vor 16 Jahren

Ich habe eine Lösung gefunden, die mir besser gefällt als Reflection. Was haltet ihr hiervon:

using System;
using System.Threading;

namespace ProxyTest
{
   class Program
   {
      static void Main()
      {
         MyPluginClass mpc = new MyPluginClass();
         mpc.InitializeLedGrid();
         // Verhindert das selbsttätige Schliessen des Konsolenfensters.
         Console.WriteLine("\nBeenden mit Return");
         Console.ReadLine();
      }
   }

   // Flexible Klasse,
   // die alles mögliche mit dem LED-Grid anstellen kann.
   public class MyPluginClass : PluginAdapter
   {
      public override void InitializeLedGrid()
      {
         base.InitializeLedGrid();
      }

      protected override void Plugin(object state)
      {
         /* Simuliert Berechnungen
         * und Zustandsänderungen am LED-Array. */
         Grid.DummyProperty = "Hallo";         
      }
   }

//============= Ab hier vorgefertigte Klassen ============

   /// <summary>
   /// Stellt Objekte zur Verfügung,
   /// die eine leichte Anbindung an das LED-Grid ermöglichen.
   /// </summary>
   public abstract class PluginAdapter
   {
      public LedGrid Grid
      {
         get { return new LedGrid(); }
      }

      public delegate void PluginCallback(object state);

      public virtual void InitializeLedGrid()
      {
         Grid.InvokeThread(new PluginCallback(Plugin));
      }

      protected abstract void Plugin(object state);
   }

   // Die eigentliche Ausführungs-Schicht
   public class LedGrid
   {      
      // Simuliert das eigentliche LED-Grid
      private static string dummyLedArray = string.Empty;
      public string DummyProperty
      {
         get { return dummyLedArray; }
         set { dummyLedArray = value; }
      }

      public void InvokeThread(PluginAdapter.PluginCallback Plugin)
      {
         ThreadPool.QueueUserWorkItem(new WaitCallback(Plugin));
         while(DummyProperty.Equals(string.Empty))
            ;
         // Simuliert die Aktualisierung des Displays:
         Console.WriteLine(dummyLedArray);
      }
   }
}
U
userid4382 Themenstarter:in
239 Beiträge seit 2006
vor 16 Jahren

Gestern abend fragte ich mich, ob diese Struktur einem der bekannten Design patterns entspricht und so blätterte ich im Buch Head first Design patterns - und tatsächlich, auf Seite 612 ff. wurde ich fündig. Ich hatte, ohne es zu wissen, das Bridge Pattern neu erfunden. 8)
Was die Vor- und Nachteile dieses Musters betrifft, möchte ich kurz das Buch zitieren:
_Vorteile

  • Entkoppelt eine Implementierung, so daß sie nicht permanent an eine Schnittstelle gebunden ist.
  • Abstraktion und Implementierung lassen sich unabhängig voneinander erweitern.
  • Veränderungen an den konkreten Abstraktionsklassen haben keinen Einfluß auf den Client.

Verwendung und Nachteile

  • Nützlich für grafische und fensterbasierte Systeme, die auf vielen Plattformen laufen sollen.
  • In jedem Fall nützlich, wenn sie eine Schnittstelle und eine Implementierung auf unterschiedliche Weise variieren müssen.
  • Erhöht die Komplexität._
    Zitat Ende
    Tja und wenn ich im nächsten Schritt auf der Provider-Base (hier LedGrid) noch Events zur Verfügung stelle, habe ich sogar eine Kombi aus Bridge- und Observer-Pattern (in der .net-Variante).

Was haltet ihr vom Bridge Pattern? Welche Erfahrungen habt ihr damit? Zur Zeit bin ich begeistert davon, denn es entkoppelt Basis-Objekt(e) und Funktionserweiterung(en) voneinander. Beides kann unabhängig voneinander verändert/erweitert werden.
Na wie cool ist das denn? 8)

4.207 Beiträge seit 2003
vor 16 Jahren

Hmmm ... das Bridge-Pattern. Das ist eines, was ich seit Ewigkeiten versuche, zu verstehen, aber ich hab immer das Gefühl, ich bekomm den Knackpunkt nicht ...

Es ist ja verwandt mit Decorator und Proxy, die beiden sind mir auch sonnenklar, aber bei Bridge fehlt mir irgendwie was ...

Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de