2010-12-19 14 views
2

学習のために、私はソケットベースのクライアント/サーバアプリケーションを書いています。私はパケットを正しく処理できるようにカスタムプロトコルを設計しました。今日のコードの一部を調べているうちに、自分のデータパケットを作成する私の方法には、多くの冗長なコードが含まれていることに気付きました。私はここでどのデザインパターンを使うべきですか

私はさまざまなタイプのパケットを持っています。 ImagePacket、MessagePacketなどがあります。すべての型の作成は小さなものでのみ異なり、たとえばヘッダと区切りの作成は同じです。これを改善する

、私はこのような溶液(簡体字)を思い付いた:

abstract class Packet 
{ 
public Packet(object o) 
{ 
MemoryStream memoryStream = new MemoryStream();   

AddHeader(ref memoryStream); 
AddData(ref memoryStream, obj); 
AddDelimiter(ref memoryStream); 
_packetBytes = memoryStream.ToArray(); 

memoryStream.Close(); 
} 
protected abstract void AddData(ref MemoryStream ms, object obj); 

はaddheaderとAddDelimiterを抽象的に定義されているのに対し、AddData関数メソッドが抽象メソッドとして実装され、具象クラスでオーバーライドされますクラスパケットそのもの。

これはうまく動作し、以前と同じくらい重複したコードはありませんが、 は、ImagePacketコンストラクタに文字列を渡してはいけないことを明確にしていないため、AddDataにオブジェクトを渡しています。

// correct 
Packet myMsgPacket = new MessagePacket("hello world"); 
Packet myImagePacket = new ImagePacket(image); 
// wrong, but will be compiled :(
Packet myChaosPacket = new ImagePacket("muaha you're doomed"); 

正しいデータ型が渡されているかどうかをチェックする必要があった場合は、もう一度たくさんの愚かなコードで終了します。 重複したコードを減らすことはできますが、上記の問題を解決するにはどうすればよいですか?

答えて

3

あなたは工場出荷時のパターン

Packet MyPacket = MyPacketFactory.CreatePacket(Data) 

MyFactory.CreatePacketが、その後IPacket

アップデート返す使用する必要があるようにこれが聞こえる:以下のコメントごとに、私は明確にしてきたはずですとしてを。あなたの工場は...異なるデータ型を取るオーバーロードさCreatePacket()メソッドの数を持っている

IPacket CreatePacket(Image Data) {} 
IPacket CreatePacket(String Data) {} 
IPacket CreatePacket(Exception Data) {} 

とあなただけの文字列(例:メッセージパケット、ステータスパケットまたは類似の)あなたが含まれているパケットの複数の種類を持っている場合することができます例えばAddDelimiter() - - あなたの中のパケットの工場を文字列パケットが望まれ示す列挙...

IPacket CreatePacket(String Data, StringPacketTypesEnum PacketType) {} 

を作成することができ、あなたは一般的なすべての重複したコードを扱う機能を有することができるこれはあなたのコードを維持しますDRY

+0

質問は、どのデータパラメータを使用できるかについてです。ユーザーは、Dataが文字列かイメージかを知りたいと思う。 –

+0

おそらく私はもっとはっきりしていたはずですが、もちろん、それは可能です - 私は異なるデータ型とおそらくは文字列データのための追加の 'enum'型 – Basic

0

Ruby on Railsはこれを解決するために検証を使用しています。

addData()関数が入力でvalidate()を呼び出した場合は、各サブクラスでvalidate()をオーバーライドするだけで済みます。

0

インターフェイスを返すファクトリパターンに行きます。

さらに、参照型にrefを使用する必要はありません。

0

あなたの現在の解決策はOKだと思います。 ImagePacketコンストラクタに渡されるデータのタイプをImageタイプに絞り込む必要があります。例:

class ImagePacket : Packet{ 
    public ImagePacket(Image img) : base(img){} 
} 

これは、データがコピア時に画像であることを確認します。もちろん、実際にobjectタイプを渡さなければならない場合、これは機能しない可能性があります。

関連する問題