7

switchステートメントを避けたかったのです。30以上のドキュメントタイプがあります。今後、さらにドキュメントタイプを追加する必要がある可能性もあります。IDocumentを渡し、IDocumentの実装で指定されたタイプを使用したいと思います。私が言及するのを忘れた他の何かはProgressNoteViewModel、LabViewModelでした...すべてWorkspaceViewModelから継承し、すべての具象実装コンストラクターはパラメーターとしてタイプIPatientを取ります。IoCコンテナとしてCastleも使用しています

コードを次のようなものにリファクタリングしたいと思います

viewModel = new TreeViewModel(repository.GetPatientDocumentListing(IDocumentType);
this.DocTreeViewModel = viewModel;
//How would I then be able to instantiate the right ViewModel
//based on IDocumentType and also pass a object into the
//constructor that is not know at compile time

私は次のコードを持っています:

switch (docType)
{
    case "ProgressNotes":
        viewModel = new TreeViewModel(repository.GetPatientProgressNotes());
        this.DocTreeViewModel = viewModel;
        ProgressNoteViewModel workspace = ProgressNoteViewModel.NewProgressNoteViewModel(_patient);
        break;
    case "Labs":
        viewModel = new TreeViewModel(repository.GetPatientLabs());
        this.DocTreeViewModel = viewModel;
        LabViewModel workspace = LabViewModel.NewLabViewModel(_patient);
        break;
}
this.Workspaces.Add(workspace);
this.SetActiveWorkspace(workspace);
4

2 に答える 2

4

完全にテストされていません:

public class ViewModelBuilderFactory
{
    public IViewModelBuilder GetViewModelBuilder (string docType, IRepository repository)
    {
        switch (docType)
        {
            case "ProgressNotes":
                return new ProgressNotesViewModelBuilder(repository);
            case "Labs":
                return new LabsViewModelBuilder(repository);
            default:
                throw new ArgumentException(
                    string.Format("docType \"{0}\" Invalid", docType);
        }
    }
}

public interface IViewModelBuilder
{
    TreeViewModel GetDocTreeViewModel();
    WorkSpace GetWorkSpace(Patient patient);
}

public class LabsViewModelBuilder : IViewModelBuilder
{
    private IRepository _repository;
    public LabsViewModelBuilder(IRepository repository)
    {
        _repository = repository;
    }

    public TreeViewModel GetDocTreeViewModel()
    {
        return new TreeViewModel(_repository.GetPatientLabs());
    }

    public Workspace GetWorkspace(Patient patient)
    {
        return LabViewModel.NewLabViewModel(patient);
    }
}

public class ProgressNotesViewModelBuilder : IViewModelBuilder
{
    private IRepository _repository;
    public ProgressNotesViewModelBuilder(IRepository repository)
    {
        _repository = repository;
    }

    public TreeViewModel GetDocTreeViewModel()
    {
        return new TreeViewModel(_repository.GetPatientProgressNotes());
    }

    public Workspace GetWorkspace(Patient patient)
    {
        return ProgressNoteViewModel.NewProgressNoteViewModel(patient);
    }
}

これで、呼び出しコードは次のようになります。

ViewModelBuilderFactory factory = new ViewModelBuilderFactory();
IViewModelBuilder modelBuilder = factory.GetViewModelBuilder(docType, repository);
this.DocTreeViewModel = modelBuilder.GetDocTreeViewModel();
Workspace workspace = modelBuilder.GetWorkspace(patient);
this.Workspaces.Add(workspace);
this.SetActiveWorkspace(workspace);

[最初の投稿から4回の編集。間違いを見続ける]

[CastleIOCを使用していることに注意してさらに編集]

Castle xml構成で、追加することができます(ここでは、Castleに関する漠然とした知識のみに取り組んでいます)。

<component id="ProgressNotesViewModelBuilder"
           type="MyNamespace.ProgressNotesViewModelBuilder, MyAssembly">
    <parameters>
        <!-- reference to repository here -->
    </parameters>
</component>
<component id="LabsViewModelBuilder"
           type="MyNamespace.LabsViewModelBuilder, MyAssembly">
    <parameters>
        <!-- reference to repository here -->
    </parameters>
</component>

次に、ViewModelBuilderFactoryは必要ありません。置き換えるだけで、

IViewModelBuilder modelBuilder = factory.GetViewModelBuilder(docType, repository);

IViewModelBuilder modelBuilder = (IViewModelBuilder)
    container.Resolve(docType + "ViewModelBuilder");

これで、switchステートメントはまったく必要ありません。

ただし、スイッチは悪臭ではなく、悪臭がするだけであり、すべての悪臭と同様に、悪臭のあるものすべてから隔離する必要があることに注意してください。それがファクトリパターンが達成しようとしていることです。

于 2010-02-21T00:10:19.093 に答える
1

IoCコンテナの代わりに、戦略とファクトリパターンを組み合わせようとします。ケースごとにカスタムコンストラクターパラメーターが必要な場合は、配線付きの適切なIoCコンテナーが必要であると想定します。

class ViewModelBuilderFactory
{
    private Dictionary<string, System.Type> resolver;

    public void ViewModelBuilderFactory()
    {
        resolver = new Dictionary<string, Type>
        {
            {"ProgressNotes", typeof(ProgressNotesViewModelBuilder)},
            {"Labs", typeof(LabsViewModelBuilder)}
        };
    }

    public IViewModelBuilder GetViewModelBuilder(string key)
    {
        System.Type type = this.resolver[key];
        return (IViewModelBuilder)Activator.CreateInstance(type);
    }

}

編集

Castle Windsorを使用して上記の回答を参照すると、次のコードは、名前付きコンポーネントを使用して同じことを実行できますが、コードで初期化されます。

container.Register(Component
.For<IViewModelBuilder>()
.ImplementedBy<ProgressNotesViewModelBuilder>()
.Named("ProgressNotes"));
container.Register(Component
.For<IViewModelBuilder>()
.ImplementedBy<LabsViewModelBuilder>()
.Named("Labs"));

var builder = container.Resolve<IViewModelBuilder>(key);
于 2012-05-30T12:54:10.273 に答える