简体   繁体   English

C#工厂模式

[英]C# Factory Pattern

I am building a search application that has indexed several different data sources. 我正在构建一个索引几个不同数据源的搜索应用程序。 When a query is performed against the search engine index, each search result specifies which data source it came from. 当针对搜索引擎索引执行查询时,每个搜索结果指定它来自哪个数据源。 I have built a factory pattern that I used to display a different template for each type of search result, but I've realized that this pattern will become more difficult to manage as more and more data sources are indexed by the search engine (ie new code template has to be created for each new data source). 我已经构建了一个工厂模式,我用它为每种类型的搜索结果显示不同的模板,但我意识到这种模式将变得更难以管理,因为越来越多的数据源被搜索引擎索引(即新的必须为每个新数据源创建代码模板。

I created the following structure for my factory based off of an article by Granville Barnett over at DotNetSlackers.com 我根据Granville Barnett在DotNetSlackers.com上发表的一篇文章为我的工厂创建了以下结构

factory pattern http://img11.imageshack.us/img11/8382/factoryi.jpg 工厂模式http://img11.imageshack.us/img11/8382/factoryi.jpg

In order to make this search application easier to maintain, my thought was to create a set of database tables that can be used to define individual template types that my factory pattern could reference in order to determine which template to construct. 为了使这个搜索应用程序更易于维护,我的想法是创建一组数据库表,可用于定义我的工厂模式可以引用的各个模板类型,以确定要构造的模板。 I figured that I'd need to have a look up table that would be used to specify the type of template to build based off of the search result data source. 我想我需要有一个查找表,用于根据搜索结果数据源指定要构建的模板类型。 I'd then need to have a table(s) to specify which fields to display for that template type. 然后,我需要有一个表来指定要为该模板类型显示的字段。 I'd also need a table (or additional columns within the template table) that would be use to define how to render that field (ie Hyperlink, Label, CssClass, etc). 我还需要一个表(或模板表中的其他列),用于定义如何呈现该字段(即超链接,标签,CssClass等)。

Does anyone have any examples of a pattern like this? 有没有人有这样的模式的例子? Please let me know. 请告诉我。 Thanks, -Robert 谢谢,-Robert

I would offer that this proposed solution is no less maintainable than simply associating a data source to the code template, as you currently have now. 我建议这个提议的解决方案不仅仅是简单地将数据源与代码模板相关联,就像你现在所拥有的那样。 In fact, I would even go so far as to say you're going to lose flexibility by pushing the template schema and rendering information to a database, which will make your application harder to maintain. 实际上,我甚至会说通过推送模板架构和将信息呈现到数据库来失去灵活性,这将使您的应用程序更难维护。

For example, let's suppose you have these data sources with attributes (if I'm understanding this correctly): 例如,假设您有这些具有属性的数据源(如果我正确理解这一点):

Document { Author, DateModified }
Picture { Size, Caption, Image }
Song { Artist, Length, AlbumCover }

You then may have one of each of these data sources in your search results. 然后,您可以在搜索结果中包含其中一个数据源。 Each element is rendered differently (Picture may be rendered with a preview image anchored to the left, or Song could display the album cover, etc.) 每个元素的呈现方式都不同(图片可以使用固定在左侧的预览图像进行渲染,或者歌曲可以显示专辑封面等)

Let's just look at the rendering under your proposed design. 让我们看看你提出的设计下的渲染。 You're going to query the database for the renderings and then adjust some HTML you are emitting, say because you want a green background for Documents and a blue one for Pictures. 您将查询数据库中的渲染,然后调整您正在发出的一些HTML,比如因为您想要一个绿色背景的文档和一个蓝色的图片。 For the sake of argument, let's say you realize that you really need three background colors for Songs, two for Pictures, and one for Documents. 为了争论,让我们说你意识到你真的需要三种背景颜色的歌曲,两种用于图片,一种用于文档。 Now, you're looking at a database schema change, which is promoted and pushed out, in addition to changing the parameterized template you're applying the rendering values to. 现在,除了更改要应用渲染值的参数化模板之外,您还在查看数据库模式更改(已提升并推出)。

Let's say further you decide that the Document result needs a drop-down control, the Picture needs a few buttons, and Songs need a sound player control. 让我们进一步说你决定Document结果需要一个下拉控件,Picture需要几个按钮,而歌曲需要一个声音播放器控件。 Now, each template per data source changes drastically, so you're right back where you started, except now you have a database layer thrown in. 现在,每个数据源的每个模板都会发生巨大变化,所以你就可以回到原来的位置了,除非你现在有一个数据库层。

This is how the design breaks, because you've now lost the flexibility to define different templates per data source. 这就是设计中断的方式,因为您现在已经失去了为每个数据源定义不同模板的灵活性。 The other thing you lose is having your templates versioned in source control. 您丢失的另一件事是在源代码管理中对模板进行版本控制。

I would look at how you can re-use common elements/controls in your emitted views, but keep the mapping in the factory between the template and the data source, and keep the templates as separate files per data source. 我将看看如何在发出的视图中重用通用元素/控件,但是在工厂中保留模板和数据源之间的映射,并将模板作为单独的文件保存在每个数据源中。 Look at maintaining the rendering via CSS or similar configuration settings. 看看通过CSS或类似的配置设置维护渲染。 For making it easier to maintain, considering exporting the mappings out as a simple XML file. 考虑将映射作为简单的XML文件导出,使其更易于维护。 To deploy a new data source, you simply add a mapping, create the appropriate template and CSS file, and drop them in to expected locations. 要部署新数据源,只需添加映射,创建相应的模板和CSS文件,然后将它们放入预期的位置。

Response to comments below: 回复以下评论:

I meant a simple switch statement should suffice: 我的意思是一个简单的switch语句就足够了:

switch (resultType)
{
    case (ResultType.Song):
      factory = new SongResultFactory();
      template = factory.BuildResult();
      break;
    // ...

Where you have the logic to output a given template. 您有逻辑输出给定模板的位置。 If you want something more compact than a long switch statement, you can create the mappings in a dictionary, like this: 如果你想要一个比long switch语句更紧凑的东西,你可以在字典中创建映射,如下所示:

IDictionary<ResultType, ResultFactory> TemplateMap;
mapping = new Dictionary<ResultType, ResultFactory>();
mapping.Add(ResultType.Song, new SongResultFactory());
// ... for all mappings.

Then, instead of a switch statement, you can do this one-liner: 然后,您可以执行以下操作,而不是使用switch语句:

template = TemplateMap[resultType].CreateTemplate();

My main argument was that at some point you still have to maintain the mappings - either in the database, a big switch statement, or this IDictionary instance that needs to be initialized. 我的主要论点是,在某些时候你仍然需要维护映射 - 无论是在数据库中,是一个大的switch语句,还是需要初始化的这个IDictionary实例。

You can take it further and store the mappings in a simple XML file that's read in: 您可以进一步将映射存储在一个简单的XML文件中,该文件可以读入:

<TemplateMap>
    <Mapping ResultType="Song" ResultFactoryType="SongResultFactory" />
    <!-- ... -->
</TemplateMap>

And use reflection et. 并使用反射等。 al. 人。 to populate the IDictionary. 填充IDictionary。 You're still maintaining the mappings, but now in an XML file, which might be easier to deploy. 您仍在维护映射,但现在在XML文件中,可能更容易部署。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM