7

私はこの問題の解決策を見つけるために今いくつかを見回しました。私はそれを解決できるいくつかの方法を見つけましたが、正直なところ、それを解決する「正しい」C#またはOOPの方法と見なされる方法のどれかを知りませんでした。私の目標は、問題を解決するだけでなく、優れたコード標準のセットを開発することでもあり、この問題を処理するための標準的な方法があると確信しています。

それぞれのクラスと通信方法を備えた2種類のプリンタハードウェアがあるとします。PrinterType1、PrinterType2です。

また、必要に応じて、後で別のタイプを追加できるようにしたいと思います。抽象化の一歩は、それらに多くの共通点があります。例として、それぞれに文字列を送信できるはずです。どちらにも共通の変数と各クラスに固有の変数があります。(たとえば、1つはCOMポートを介して通信し、そのようなオブジェクトを持っていますが、もう1つはTCPを介して通信し、そのようなオブジェクトを持っています)。

ただし、これらすべてのプリンターのリストを実装し、リストを調べて、タイプに関係なくすべてのプリンターで「送信(文字列メッセージ)」として実行できるようにしたいと思います。また、両方のオブジェクトで同じ「PrinterList [0] .Name」のような変数にアクセスしたいのですが、オブジェクト自体に固有のデータにアクセスしたい場所もあります(たとえば、の設定ウィンドウであるオブジェクトにCOMポート名が設定され、別のオブジェクトにIP /ポート番号が設定されているアプリケーション)。

つまり、簡単に言うと、次のようになります。

共通:

  • 名前
  • 送信()

PrinterType1に固有:

  • ポート

PrinterType2に固有:

  • IP

たとえば、存在するオブジェクトのタイプや数に関係なく、すべてのオブジェクトに対してSend()を実行したいと思います。

ポリモーフィズム、ジェネリックス、インターフェイスなどについて読んだことがありますが、基本的に、これがC#(および/または一般的なOOP)で通常どのように処理されるかを知りたいと思います。

私は実際に基本クラスを作ろうとしましたが、それは私にはまったく正しくないようでした。たとえば、基本クラス自体で「string Send(stringMessage)」関数を使用していません。では、そもそも基本クラスの関数を使用しないのに、派生クラスでオーバーライドする必要があるものを定義するのはなぜですか?

どんな答えにも本当に感謝しています。このあたりの人々は非常に知識が豊富で、この場所は私に多くの解決策を以前に提供してくれました。今、私はついに答えて投票するためのアカウントを手に入れました。

編集:

さらに説明すると、実際のプリンタータイプのオブジェクトにもアクセスできるようにしたいと思います。たとえば、SerialPortオブジェクトであるPrinterType1のPort変数。次のようにアクセスしたいと思います。 PrinterList[0].Port.Open()

基盤となるポートのすべての機能にアクセスできます。同時に、さまざまなオブジェクトに対して同じように機能するジェネリック関数を呼び出したいと思います(ただし、実装は異なります)。

foreach (printer in Printers)
    printer.Send(message)
4

5 に答える 5

10

インターフェイスを使用した疑似例。

public interface IPrinter
{
   void Send();
   string Name { get; }
}

public class PrinterType1 : IPrinter
{
  public void Send() { /* send logic here */ }
  public string Name { get { return "PrinterType1"; } }
}

public class PrinterType2 : IPrinter
{
  public void Send() { /* send logic here */ }
  public string Name { get { return "Printertype2"; } }

  public string IP { get { return "10.1.1.1"; } }
}


// ...
// then to use it
var printers = new List<IPrinter>();

printers.Add(new PrinterType1());
printers.Add(new PrinterType2());

foreach(var p in printers)
{
  p.Send();

  var p2 = p as PrinterType2;

  if(p2 != null) // it's a PrinterType2... cast succeeded
    Console.WriteLine(p2.IP);
}
于 2012-12-03T16:19:34.637 に答える
2

あなたが探しているのは、次のような抽象基本クラスです。

abstract class Printer
{
    public string Name { get; set; }
    public abstract string Send(string Message);
}

次に、そのクラスから継承し、必要に応じて Send() 関数を実装します。

ここでもインターフェイスを使用できます。違いは、インターフェイスは、継承者が実装する必要があるプロパティ、メソッド、およびイベントのみを指定できることです。コード自体は実装しません。どちらを使用するかは、アプリケーションに最適なものによって異なります。両方を行うことになるかもしれません (インターフェースを実装する抽象クラスを作成します)。

于 2012-12-03T16:19:54.300 に答える
2

IPrinterType「一般的な」メソッドを保持するインターフェース(たとえば )を作成し、代わりにこのインターフェースを使用します。

于 2012-12-03T16:18:36.050 に答える
1

「たとえば、基本クラス自体で「文字列 Send(string Message)」関数を使用していないという特定の質問について。そもそも基底クラスの関数?」

基本クラスに実装する必要はありません。

基本クラスが抽象クラスの場合は、単純に宣言してから、具象クラスに任せて実装することができます。

具体的な実装を提供したくない場合は、抽象クラスの代わりに、すべての具体的なクラスが実装する必要があるインターフェイスを使用する方がよい場合があります。

于 2012-12-03T16:21:55.857 に答える
0

あなたが説明しているのは、設計されたインターフェイスのほとんどです。すべての一般的なプロパティ/メソッドをそれに入れ、具体的な実装を非表示にします。Printer共有できる同様のコードが明らかに存在するため、基本クラスを使用することをお勧めします。

ポート/IP など、言及するより定義されたプロパティに関しては、どのタイプを扱っているかを知る必要があります。その時点で、正しい型にキャストできます。

于 2012-12-03T16:19:43.153 に答える