インタフェースの代わりにデリゲートをつかう
C# 3.0 でデリゲートとラムダ式を使った、テンプレートメソッドパターンっぽいコードを書いてみました。
※中の処理には意味はありませんが…
エントリポイント
Program.cs
namespace HogeApp { class Program { public static void Main(string[] args) { // 処理実行 Facade.DoWork(); } } }
ファサードクラス と クロージャのファクトリクラス
Facade.cs
PostSelectFactory.cs
SelectFactory.cs
PostSelectFactory.cs
using System; using System.Collections.Generic; namespace HogeApp { public static class Facade { public static void DoWork() { // サービスオブジェクト IService service = ServiceFactory(); // データ用のオブジェクト変数 IList<IMember> list = ListFactory(); ///////////////////////////////////////////////////////// // 振る舞いの設定を行います // 前段処理の設定 service.PreSelect = PreSelectFactory.GetPreSelect(list); // メイン処理の設定 service.Select = SelectFactory.GetSelect(list); // 後段処理の設定 service.PostSelect = PostSelectFactory.GetPostSelect(list); // 出力処理の設定 service.Outputer = OutputerFactory.GetOutputer(list); ///////////////////////////////////////////////////////// // 処理実行 Console.WriteLine("-- program start --"); // サービスオブジェクト実行 service.Execute(); Console.WriteLine("-- program end --"); // コンソール一時停止 Console.ReadLine(); } // サービスオブジェクト生成 private static IService ServiceFactory() { IService service = SkeletonService.GetInstance(); service.PersonsFactory = () => PersonsFactory.GetPersons(); return service; } // データ用のリストオブジェクト作成 private static IList<IMember> ListFactory() { return new List<IMember>(); } } } using System; using System.Collections.Generic; namespace HogeApp { public static class PreSelectFactory { public static Func<IPerson, IList<IMember>> GetPreSelect(IList<IMember> list) { return (person) => { Console.WriteLine("-- is called PreSelect."); // 年齢30才以上をデータリストに追加 if (person.Age > 30) { list.Add(new Member(new Person(person.Name, person.Age), "over 30")); } return list; }; } } } using System; using System.Collections.Generic; namespace HogeApp { public static class SelectFactory { public static Func<IPerson, IList<IMember>> GetSelect(IList<IMember> list) { return (person) => { Console.WriteLine("-- is called Select."); // 名前にaが含まれる人をデータリストに追加 if (person.Name.IndexOf("a") != -1) { list.Add(new Member(new Person(person.Name, person.Age), "include a")); } return list; }; } } } using System; using System.Collections.Generic; namespace HogeApp { public static class PostSelectFactory { public static Func<IPerson, IList<IMember>> GetPostSelect(IList<IMember> list) { return (person) => { Console.WriteLine("-- is called PostSelect."); // 名前にyが含まれる人をデータリストに追加 if (person.Name.IndexOf("y") != -1) { list.Add(new Member(new Person(person.Name, person.Age), "include y")); } return list; }; } } }
サービスオブジェクト すべて抽象に対してプログラミングされます
IService.cs
SkeletonService.cs
using System; using System.Collections.Generic; namespace HogeApp { public interface IService { Func<IList<IPerson>> PersonsFactory { set; } Action Outputer { set; } Func<IPerson, IList<IMember>> PreSelect { set; } Func<IPerson, IList<IMember>> Select { set; } Func<IPerson, IList<IMember>> PostSelect { set; } void Execute(); } } using System; using System.Collections.Generic; namespace HogeApp { public class SkeletonService : IService { // フィールド (※自分のインスタンス変数以外は全て抽象) private static SkeletonService instance; private Func<IList<IPerson>> personsFactory; private Action outputer; private Func<IPerson, IList<IMember>> preSelect; private Func<IPerson, IList<IMember>> select; private Func<IPerson, IList<IMember>> postSelect; // プロパティ (※外部から具体的な振る舞いを設定してもらう) public Func<IList<IPerson>> PersonsFactory { set { this.personsFactory = value; } } public Action Outputer { set { this.outputer = value; } } public Func<IPerson, IList<IMember>> PreSelect { set { this.preSelect = value; } } public Func<IPerson, IList<IMember>> Select { set { this.select = value; } } public Func<IPerson, IList<IMember>> PostSelect { set { this.postSelect = value; } } // コンストラクタは封印 private SkeletonService() { } // スタティックファクトリメソッド public static SkeletonService GetInstance() { if (instance == null) { instance = new SkeletonService(); // デリゲートの初期化 instance.PersonsFactory = () => null; instance.Outputer = () => { }; instance.PreSelect = (person) => null; instance.Select = (person) => null; instance.PostSelect = (person) => null; } return instance; } // 唯一の実行メソッド public void Execute() { Console.WriteLine("-- is called SkeletonService#Execute."); // オブジェクトを生成する振る舞いの実行 IList<IPerson> persons = personsFactory(); // リスト用のオブジェクト変数 IList<IMember> list = null; // 振る舞い毎に個別のループで処理を実行する // リストが返される部分とか気持ち悪い… // 抽象に対して処理の構造を決めている foreach (IPerson person in persons) { list = preSelect(person); } foreach (IPerson person in persons) { list = select(person); } foreach (IPerson person in persons) { list = postSelect(person); } Console.WriteLine("リストカウントは : " + list.Count); // 出力という振る舞いのみが操作出来ればいい outputer(); } } }
エンティティっぽいの
IPerson.cs
Person.cs
using System; namespace HogeApp { public interface IPerson { String Name { get; } int Age { get; } } } using System; namespace HogeApp { public class Person : IPerson { String name; int age; public Person(String name, int age) { this.name = name; this.age = age; } public String Name { get { return name; } } public int Age { get { return age; } } } }
DTOっぽいの
IMember.cs
Member.cs
using System; namespace HogeApp { public interface IMember { String Text { get; } String Name { get; } } } using System; namespace HogeApp { public class Member : IMember { String text; IPerson person; public Member(IPerson person, String text) { this.person = person; this.text = text; } public String Text { get { return text; } } public String Name { get { return person.Name; } } } }
関数オブジェクトとか
PersonsFactory.cs
MembersOutputer.cs
using System.Collections.Generic; namespace HogeApp { public static class PersonsFactory { public static IList<IPerson> GetPersons() { return new List<IPerson> { new Person("hoge", 28), new Person("piyo", 32), new Person("yazz", 46) }; } } } using System; using System.Collections.Generic; namespace HogeApp { public static class MembersOutputer { public static void Execute(IList<IMember> list) { Console.WriteLine("選択された人達"); foreach (Member m in list) { Console.WriteLine(m.Name + " : なぜ? " + m.Text); } } } }