代码之家  ›  专栏  ›  技术社区  ›  Marc Gravell

通过IOC影响AOP属性;代码味道还是优雅?

  •  8
  • Marc Gravell  · 技术社区  · 15 年前

    我在用 StructureMap 目前,一般以惯例为基础( Scan() )自动配置,我希望在管道中添加基于装饰器的缓存。

    如果我手动配置它,那没问题,但是 扫描() 就是这样 方便的 当你得到很多依赖…我在玩弄什么缓存 建议 在接口上,例如:

    public interface IFoo {
        [CacheDuration(20)] // cache for 20 minutes
        string[] DoSomethingReusable();
    
        SomeType DoSomethingNonReusable(int key); // not cached
    }
    

    其理念是通过在 结构图 的扫描(非常简单),它可以发现一个或多个方法被修饰以用于缓存,并自动将生成的缓存修饰器插入到该类型的管道中(从接口/方法名称和参数值生成缓存键)。

    另一方面,它使添加缓存变得非常轻松——只需稍微修饰一下界面;但这是一种代码味道吗?我是在复制已经解决的问题吗?

    7 回复  |  直到 14 年前
        1
  •  7
  •   Krzysztof Kozmic    15 年前

    如果您知道两个主要因素,属性就可以了:

    • 本质上分散的结构,而不是在一个地方,元数据散布在它接触的每个组件上。

    • 刚性编译器常量结构。如果突然决定缓存持续时间应该是10而不是20,那么必须重新编译所有代码。您可以将属性路由到config之类的东西,但这是围绕属性工作的,此时您应该真正重新考虑使用它们是否是最好的主意。

    只要你意识到这些问题,并对它们表示同意,就可以继续下去。

        2
  •  5
  •   Mark Seemann    15 年前

    据我所知,您主要考虑添加属性以使容器注册更容易。您仍在使用decorator设计模式实现缓存,这是imo实现缓存的正确方法。

    我们在safewhere也这么做,但是我们使用 基于约定 改为注册。我们还使用了Castle Windsor,所以我不知道这是否适用于structuremap,但是我们只是用任何命名的东西扫描适当的程序集。 Caching*Repository 把它们注册为真正的仓库的装饰师。我们还有一个基于约定的单元测试,它验证所有必需的缓存存储库是否存在。

    添加自定义属性是否是一种代码味道取决于代码的可重用性程度。我的经验法则是我想成为 能够的 把所有东西都连接起来 穷人的迪 .我仍然使用DI容器,但是这个规则为我提供了一个健全性检查。

    一般来说,我不喜欢将我的代码耦合到一个特定的容器,但是我不能真正弄清楚您是否在这里这样做。这取决于是否需要引用structuremap来定义自定义属性。如果你必须参考结构图,我会认为它是一种气味。

        3
  •  2
  •   Gerrie Schenck    15 年前

    我在这里看到的唯一缺点是没有缓存对象的中心点。通常有一个特定的层完成缓存。用你的技术,情况并非如此。

    我还认为您的代码有责任决定是否应该缓存某些内容,而不是类/接口。

    但要回答你的问题,这是一种代码味道吗?我会说不,但一旦这个系统在很多地方被使用,新开发人员就可能难以掌握它的窍门。

        4
  •  1
  •   Noon Silk    15 年前

    我不能说我完全理解每件事,但就我的2美分而言,这似乎可以说是好的;但我只是想知道,在不重新编译的情况下,是否很容易改变它。也许您希望通过配置条目而不是编译来更改缓存持续时间。我可能会将这些数据存储在一个我可以轻松配置的地方。(也许我误解了…)

        5
  •  1
  •   Pieter Germishuys    15 年前

    我倾向于同意关于缓存的说法必须由您的代码决定,但另一种情况是,我认为您可能需要考虑“需要缓存什么,整个对象?”

    您可能想玩弄这样一个想法:让属性设置不想缓存对象的成员。

    也许是属性

    [Cache(Duration=20, Location(...))]
    

    ?

        6
  •  1
  •   aaron    14 年前

    我认为每当您使用属性时,应该考虑的是意图与类的耦合。一点是,您不能在缓存持续时间为10秒的同一位置使用该实体,而在另一个缓存持续时间为60秒的位置使用该实体。imho这总是任何类型属性的权衡。

        7
  •  1
  •   lomaxx    14 年前

    我参加这次聚会有点晚了,但我最近一直在考虑这个问题,总的来说, 使用属性进行缓存是一种代码味道 .

    原因如下:

    1. 按属性缓存可以让您进入一个“尾巴摇摆不定”的场景,因为它有可能在实现方法时改变代码的设计,这些方法可以让缓存属性使用它们,特别是当您进入复杂的场景时。

    2. 按属性缓存是危险的,因为尽管向缓存中添加项的过程通常是相同的(即cache.add(key,value)),但确定密钥和要插入的项的过程并不总是相同的,并且通常需要某种不总是通用的逻辑。例如,通常认为使用参数值生成缓存键,但考虑使用日期时间参数,调用方传递日期时间的情况。现在…返回值可能始终相同,但参数生成的键将不同,并且将为每个调用生成一个新的缓存对象。然后,您可以更改方法的设计,但随后您将完全了解1中描述的问题。

    3. 一般来说,缓存用于优化特定场景,很少 原因 在缓存中输入的项是相同的。假设您有一个很少更改的项目目录,您可能会决定在应用程序启动时将整个目录加载到缓存中,并将其缓存12小时,但您可能会决定仅在用户首次登录后才缓存其用户详细信息。检索这些项然后将它们添加到缓存所需的逻辑完全不同,不适合在属性中被捕获。

    4. 如果您有一个缓存属性,那么当缓存项发生更改时,您还需要一种使其过期的方法。假设您有一个缓存属性,那么您很可能会有一个“cacheExpiry”属性,它上面会有同样的问题,但是您还必须想出一种在方法之间生成缓存键的常见方法,因为更新或删除对象的参数与r向缓存中添加对象。

    归根结底,在表面上,通过属性进行缓存似乎是一个好主意,但是在实践中,缓存解决的问题的本质意味着它不适合由属性驱动。

    推荐文章