###前提・実現したいこと
以下のコードを改善したいです。
長いコードなので、経緯と意図を説明し、最後に問題のソースコードを載せます。
まず、メッセージ列挙体を受け取ってメッセージを返すGetMessageメソッドを考えました。
C#
1class MessageProvider 2 { 3 public string GetMessage(MessageKind messageKind) 4 { 5 switch (messageKind) 6 { 7 case MessageKind.TaskDone: 8 return "all tasks are done"; 9 case MessageKind.CommandLineArgumentsError: 10 return "need some command-line arguments"; 11 //... 12 } 13 } 14 } 15 16 enum MessageKind 17 { 18 TaskDone, 19 CommandLineArgumentsError 20 }
その後、メッセージだけではなく、メッセージ列挙体からメッセージのタイプ(エラー/通知)と
メッセージのIDも取得したいと考えました。
そこで、新たにGetMessageDataメソッドを考え、その内部で
getMessage,getId,getMessageLevelメソッドを呼ぶようにしました。
C#
1class MessageProvider 2 { 3 public const int FirstInfoIndex = 10001; 4 public const int FirstErrorIndex = 20001; 5 6 public MessageData GetMessageData(MessageKind messageKind) 7 { 8 return new MessageData 9 { 10 Id = getId(messageKind), 11 Message = getMessage(messageKind), 12 MessageLevel = getMessageLevel(messageKind) 13 }; 14 } 15 16 private string getMessage(MessageKind messageKind) 17 { 18 //... 19 } 20 21 private int getId(Enum messageKind) 22 { 23 return Convert.ToInt32(messageKind); 24 } 25 26 private MessageLevel getMessageLevel(Enum messageKind) 27 { 28 var id = getId(messageKind); 29 if (id < FirstInfoIndex) 30 throw new ArgumentException("implimentation error"); 31 return id < FirstErrorIndex ? 32 MessageLevel.Info : 33 MessageLevel.Error; 34 } 35 } 36 37 public class MessageData 38 { 39 public string Message { get; set; } 40 public MessageLevel MessageLevel { get; set; } 41 public int Id { get; set; } 42 } 43 44 publicenum MessageLevel 45 { 46 Info, 47 Error 48 }
ここで、メッセージはプロジェクト毎に存在するため、
メッセージ列挙体を受け取ってメッセージを返すgetMessageメソッドは
各プロジェクトに必要ですが、getMessageLevel,getId,それからGetMessageDataメソッドも
共通のアルゴリズムとして利用できることに気が付きました。
そこで以下のものを共通化して各プロジェクトから参照したいと思いました。
・MessageDataクラス
・MessageLevel列挙体
・GetMessageDataメソッド
・getIdメソッド
・getMessageLevelメソッド
また、以下のものを各プロジェクトで実装したいと思いました。
・FirstErrorIndex
・FirstInfoIndex
・getMessageメソッド
・MessageKind列挙体
上記を実現するために悩んだ挙句以下のようなコードを書きました。(全体なので非常に長いです)
Project1名前空間が多数のプロジェクトのうちの1つで、
LowLevelAssembly名前空間が共有プロジェクトです。
C#
1namespace Project1 2{ 3 class Project1MessageProvider : LowLevelAssembly.IMessageProvider 4 { 5 public const int FirstInfoIndex = 10001; 6 public const int FirstErrorIndex = 20001; 7 8 private Project1MessageKind _messageKind; 9 10 public Project1MessageProvider(Project1MessageKind messageKind) 11 { 12 _messageKind = messageKind; 13 } 14 15 public Enum MessageKind 16 { 17 get { return _messageKind; } 18 } 19 20 int LowLevelAssembly.IMessageProvider.FirstInfoIndex { get { return FirstInfoIndex; } } 21 int LowLevelAssembly.IMessageProvider.FirstErrorIndex { get { return FirstErrorIndex; } } 22 23 public string GetMessage() 24 { 25 switch (_messageKind) 26 { 27 case Project1MessageKind.TaskDone: 28 return "all tasks are done"; 29 case Project1MessageKind.CommandLineArgumentsError: 30 return "need some command-line arguments"; 31 case Project1MessageKind.SpecialError: 32 return "failed to backup log files"; 33 default: 34 throw new ArgumentException("undefined"); 35 } 36 } 37 } 38 39 enum Project1MessageKind 40 { 41 TaskDone = Project1MessageProvider.FirstInfoIndex, 42 CommandLineArgumentsError = Project1MessageProvider.FirstErrorIndex, 43 SpecialError 44 } 45} 46 47namespace LowLevelAssembly 48{ 49 public class MessageData 50 { 51 public string Message { get; set; } 52 public MessageLevel MessageLevel { get; set; } 53 public int Id { get; set; } 54 } 55 56 public enum MessageLevel 57 { 58 Info, 59 Error 60 } 61 62 public class MessageDataCreator 63 { 64 private IMessageProvider _messageProvider; 65 66 public MessageDataCreator(IMessageProvider messageProvider) 67 { 68 _messageProvider = messageProvider; 69 } 70 71 public MessageData GetMessageData() 72 { 73 var messsageKind = _messageProvider.MessageKind; 74 return new LowLevelAssembly.MessageData 75 { 76 Id = getId(_messageProvider.MessageKind), 77 Message = _messageProvider.GetMessage(), 78 MessageLevel = getMessageLevel(messsageKind) 79 }; 80 } 81 82 private MessageLevel getMessageLevel(Enum messageKind) 83 { 84 var id = getId(messageKind); 85 if (id < _messageProvider.FirstInfoIndex) 86 throw new ArgumentException("implimentation error"); 87 return id < _messageProvider.FirstErrorIndex ? 88 LowLevelAssembly.MessageLevel.Info : 89 LowLevelAssembly.MessageLevel.Error; 90 } 91 92 private int getId(Enum messageKind) 93 { 94 return Convert.ToInt32(messageKind); 95 } 96 } 97 98 public interface IMessageProvider 99 { 100 int FirstInfoIndex { get; } 101 102 int FirstErrorIndex { get; } 103 104 string GetMessage(); 105 106 Enum MessageKind { get; } 107 } 108}
このコードをどのように改善したらいいか、ご意見を下さい。
よろしくお願い致します。
##備考
以下は現在の実装に対するクライアントコードのサンプルとなります。
C#
1namespace Project1 2{ 3 class ClientClass 4 { 5 public void ClientCode() 6 { 7 var provider = new Project1MessageProvider(Project1MessageKind.TaskDone); 8 var creator = new LowLevelAssembly.MessageDataCreator(provider); 9 var messageData = creator.GetMessageData(); 10 Console.WriteLine($"ID:{messageData.Id } Level:{messageData.MessageLevel} Content:{messageData.Message}"); 11 } 12 } 13}
##※追記事項
コード全体を改善することが第一の目標なのですが、
以下のようなクライアントコードによってメッセージデータが取得できるようになれば、
更に良いだろうと思っています。
以下は一例です。
C#
1namespace Project1 2{ 3 class ClientClass 4 { 5 public void ClientCode() 6 { 7 var provider = new Project1MessageProvider(); 8 var creator = new LowLevelAssembly.MessageDataCreator(provider); 9 var messageData = creator.GetMessageData(Project1MessageKind.TaskDone); 10 Console.WriteLine($"ID:{messageData.Id } Level:{messageData.MessageLevel} Content:{messageData.Message}"); 11 } 12 } 13}
Project1MessageProviderクラスのインスタンスひとつにつきメッセージをひとつしか
取得できないような仕組みになってしまっているのは、決して意図したことではなく、
これ以外に実現方法が分からなかったからです。
本当はGetMessageメソッドの引数にはProjectMessageKind型の変数をとりたいですし、
その他のプロジェクトにおいても、そのプロジェクトに固有のメッセージ列挙体を引数としたいです。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/09/05 04:06 編集
2016/09/05 04:32
2016/09/05 05:09