2010-08-31 4 views
3

J'ai eu du mal à comprendre les cours. Même après avoir lu plusieurs sites Web et livres, je n'ai toujours pas l'impression de vraiment l'avoir.Organisation de classe vb.net

L'application sur laquelle je travaille dispose d'un sous-marin qui contrôlera quelques équipements de test différents via une interface USB vers GPIB.

Alors, je:

 
Laptop 
    USB - GPIB Interface 
     Power Supply (Device Address 5) 
     HP34970 Datalogger (Device Address 6) 

Dans mon sous, je voudrais ouvrir l'appareil GPIB, envoyer quelques commandes IPAC pour allumer l'alimentation, envoyer un peu plus au HP34970 pour passer des relais ou mesurez la tension.

Semble assez simple et je peux facilement tout faire fonctionner dans le même module. Cependant, je pense que ce serait mieux d'avoir une classe séparée pour l'interface GPIB, l'alimentation et HP34970. Si c'était le cas, je pourrais très facilement réutiliser le code dans d'autres projets.

Voici où je ne peux pas obtenir un modèle mental- Si je crée une instance de la classe GPIB et ai une méthode pour 'ouvrir' un canal au bus GPIB, comment puis-je autoriser des méthodes dans d'autres classes (comme alimentation) pour utiliser le canal ouvert créé dans la classe GPIB? Par exemple, une méthode dans la classe d'alimentation pour régler la tension.

Si quelqu'un pouvait prendre quelques minutes pour publier un pseudo code et une petite explication pour illustrer comment je pourrais/devrait organiser cela, j'apprécierais grandement l'aide!

Merci

Répondre

1

Considérez les classes comme des périphériques eux-mêmes. Le principal avantage ici serait de pouvoir réutiliser le code écrit une fois - par exemple, tous vos appareils ont des adresses, ils peuvent se connecter, tester la connexion, se déconnecter - pourquoi ne pas le faire dans une classe "Device" abstraite en hériter?

Cela pourrait être l'un des usages - écrit en C# (désolé si j'ai mal compris l'utilisation réelle :) ici, je suppose que powerupply et dataLogger sont connectés à l'interface, et l'interface à l'ordinateur portable).

public class DeviceTesting 
{ 
    private string powerSupplyAddress = "DA5"; 
    private string dataLoggerAddress = "DA6"; 

    public static void main() 
    { 

     //bring interface into life 
     DeviceInterface interface = GPIBInterface(); //example of inheritance - GPIB could be just one of the many device interfaces 

     //the constructor in PowerSupply takes on the responsibility of initializing itself 
     PowerSupply ps = new PowerSupply(powerSupplyAddress, interface); //plugged in with interface - has a reference to it 
     //you could have multiple types of data loggers - all could inherit from DataLogger, and here so does HP34970 
     //This means you can reuse the common code for data loggers, and write only the specifics for each specific device of that kind 
     DataLogger myLogger = new HP34970(dataLoggerAddress, interface); 


     //now, do whatever you do with the real devices 
     ps.SetVoltage(220); //send voltage command directly 
     interface.SendLogMessage("Interface is operational"); 
     interface.ExecuteTest("test1"); //send voltage command through interface 
     //etc... you get the idea... 
    } 
} 

Maintenant, puisque l'interface a la connaissance des dispositifs, il est en interface avec, il doit les avoir dans son constructeur (dans la conception orientée objet, aussi appelé injection de dépendance, plus précisément ici, il est injection Constructor):

public GPIBInterface : DeviceInterface //here we are reusing code that's same for all interfaces 
{ 
    //whoever attaches to this interface is responsible for registering itself with it 
    public PowerSupply Power{get;set;} 
    public DataLogger Logger{get;set;} 
    //notice here that it can work with any class that inherits from DataLogger 
    public GPIBInterface() 
    { 

    } 

    private override void TestInitialization() //as an example, we write our own testing by overriding some method in base class 
    { 
     base.TestInitialization(); //make sure that the base class checks it's ok - e.g. if it's own display is working or similar... 

     if (Power.TestConnection() == false) 
      throw new DeviceNotWorkingException(ps); 
     if (Logger.TestConnection() == false) 
      throw new DeviceNotWorkingException(_logger); 
    } 

    public void SendLogMessage(string message) 
    { 
     Logger.SendMessage(message); 
    } 

    public void ExecuteTest(string testName) 
    { 
     switch(testName) 
     { 
      case "test1": 
       Power.SetVoltage(280); 
       Logger.SendMessage("Voltage increased to 280V"); 
       break; 
     } 
    } 
} 

Fondamentalement, si vos appareils interagissent les uns avec les autres dans la « vraie vie », que cela signifie qu'ils doivent avoir une référence à l'autre appareil, ils sont connectés. Par exemple, si vous branchez PowerSupply directement à l'enregistreur, la classe PowerSupply doit avoir une référence à l'enregistreur. Mais, s'il est connecté à l'interface, puis à l'interface de l'enregistreur, le PowerSupply ne doit avoir qu'une référence à l'interface et non à l'enregistreur (puisqu'il n'est pas connecté). J'espère que vous avez l'idée - il n'est pas appelé 'orienté objet' pour rien - pensez aux classes comme objets réels - si un objet peut faire chose1, que vous devriez avoir la méthode 'thing1()' dans votre classe; Si l'objet est connecté à l'objet 441, la classe doit avoir une référence à cette classe. Suivez simplement ce principe et voyez où cela vous mène ...

Lorsque vous maîtriserez cela, votre programme bénéficiera vraiment d'un modèle d'inversion de contrôle (IoC) - de cette façon, vous définissez simplement au début ce qu'est un enregistreur, Qu'est-ce que powerSupply, qui fonctionne comme un affichage, et chaque fois que quelqu'un a besoin d'un périphérique spécifique, un conteneur IoC le fournirait. De cette façon, vous n'avez pas à réécrire le code chaque fois qu'il y a un nouveau périphérique en ville - il suffit d'enregistrer le nouveau type avec le conteneur IoC et tout fonctionne.

1

comment puis-je autoriser les méthodes dans d'autres classes (comme l'alimentation) pour utiliser le canal ouvert créé dans la classe GPIB ?

Une façon est de créer une classe composite qui détient des instances de votre classe d'alimentation et votre classe GPIB (désolé pour le C#):

public class PowerSupplyGPIBController 
{ 
    // Members 
    GPIB gpib; 
    PowerSupply powerSupply; 

    // Constructor 
    public PowerSupplyGPIBController(GPIB myGPIB, PowerSupply myPowerSupply) 
    { 
     gpib = myGPIB; 
     powerSupply = myPowerSupply; 
    } 

    // Method 
    public void SendPowerSupplyVoltage() 
    { 
     GPIB.Send(myPowerSupply.Voltage); 
    } 
} 

Fondamentalement, vous devez être GPIB et des objets concernant qui sont quelque part , et transmettre des données/messages entre eux.

+0

Cela semble trop compliqué. Si une alimentation particulière ne va être utile qu'avec un objet GPIB particulier (le périphérique GPIB auquel l'alimentation est connectée), il semblerait plus naturel que l'objet alimentation détienne lui-même une référence au contrôleur GPIB. – supercat

+0

@supercact: Je suis d'accord, c'est beaucoup de cérémonie. * Si un GPIB est le seul moyen que la classe d'alimentation communique, * le fait que la classe d'alimentation contienne une référence à un GPIB semble être le moyen logique de le faire. –

+0

@Robert Harvey: Si l'on veut être extensible à des moyens de communication autres que GPIB, le moyen de le faire serait de toujours avoir une classe GpibPowerSupply qui contient une référence au contrôleur GPIB et communique avec lui, mais l'avoir implémenter une interface iPowerSupply? Je ne comprends pas bien ce que votre classe wrapper ajoute à l'équation. – supercat

1

Je suggérerais que les constructeurs pour PowerSupply, Datalogger, etc. acceptent chacun une instance d'une classe GPIB qui fait réellement la communication. Ensuite, lorsque quelqu'un appelle MyPowersupply.SetVoltage, la routine PowerSupply.SetVoltage peut utiliser cet objet GPIB pour envoyer la requête appropriée. Si vous avez plusieurs threads, vous devez probablement utiliser des verrous pour vous assurer que les communications ne sont pas masquées. Je ne vois pas vraiment d'avantages à avoir une classe composite. Donnez simplement à chaque PowerSupply, Datalogger, etc., une instance d'une classe GPIB pouvant être utilisée pour communiquer avec le périphérique physique.