Skip to content
This repository has been archived by the owner on Mar 20, 2024. It is now read-only.

KeyPatterns

Michael Ekstrand edited this page Nov 8, 2013 · 2 revisions

This page describes some key patterns that recur in LensKit.

Factory Patterns

LensKit uses four different types of factory interfaces, each for slightly different purposes. We likely have too many types of factory, so we are considering ways to reduce the number. The patterns we have are:

  • Provider is for integration with Grapht. If we want Grapht to automatically build something using the provider paradigm, it has to be a Provider. Providers may also memoize or cache. The Provider interface comes from javax.inject, the cross-framework DI annotations and types. If something is a Provider, it is expected that Grapht will be the thing using it. We deliberately do not enable Grapht's provider injection in LensKit, so if non-evaluation code is ever directly using a Provider, there's probably something wrong.

  • Factory is used when construction is parameterized. For example, matrix accumulator factories are used to allow code to say "give me a matrix accumulator for 5000 rows". Factories do not cache.

  • Supplier is identical to Providers but carries no DI connotations. Supplier comes from Guava, and are currently primarily used in the evaluator. We use them to indicate clearly that this type does not participate in dependency injection. In the evaluator, they're used for deferred evaluation. We also use them as a way to have the soft reference event collection DAO be able to re-load the data.

  • Builders are typically for building up an immutable object (see PreferenceDomainBuilder, IndexedPreferenceBuilder, etc.). Typically, we use commons-lang3's Builder interface. Builders, like suppliers and factories, are directly used by client code.

    Recommender models, such as the item-item similarity matrix and FunkSVD model, are built by builders that implement the Provider interface instead of Builder. This makes their naming reflect their purpose — building up objects, particularly expensive ones — while still integrating with Grapht.