views:

145

answers:

3

I'm trying to understand how to implement replaceable components, or a service provider interface, in the .NET world. I suspect that I just don't know the appropriate terminology to search for.

Specifically, I'm playing around with a Matrix class that has different backends. At its simplest, a matrix provides two-parameter get and set methods and a constructor. The implementation is not important to the end user. For instance, depending on the matrices size, the matrix may be backed by an in-memory array, a file, or distributed key-value store. I would like to hide the backend implementation and allow third parties to provide new backend implementations.

An ideal API, called from IronPython, say, might be something like

a = matrix(data = 0, rows = 1000, cols = 10, backend = 'file://test.txt')
a[100, 2] = 1
print a[100, 2]

What should I be reading to understand the pattern for this type of problem?

I am playing around in F# and IronPython, but don't believe this question is specific to any particular .Net language.

+3  A: 

You want to create an interface that represents the contract that is the matrix. You'll probably end up naming it something like IMatrix. Then create several implementations of this interface: MemoryMatrix, FileMatrix, DistributedKeyValueMatrix. When you pass around the concrete implementation in your code, just refer to the interface instead of the concrete type.

Take a look at the System.Collections.Generic namespace and you'll notice a lot of the structures implement ICollection, that will give you a good example on how to implement your own interfaces and concrete implementations.

You might want to use one of two things to resolve your concrete types: Create a MatrixFactory class that can create all implementations you derive. Use a Inversion of Control container to resolve the concrete type you want.

Khalid Abuhakmeh
+6  A: 

Yes, you can create an interface IMatrix and a concrete class that implements it, like that:

type IMatrix =
    abstract Item : (int * int) -> single with get, set

type ConcreteMatrix (data:single[,])=
    interface IMatrix with
        member t.Item with get((x,y)) = data.[x,y]
                      and set((x,y)) value = do data.[x,y] <- value

let printCoordinate (x, y) (matrix : #IMatrix) =
    printf "%A" matrix.[x, y]
Stringer Bell
+3  A: 

The other answers by @Stringer and @Khalid are good.

I would just summarize by saying

  • interfaces are the mechanism to create a single API that is backed by multiple implementations, and
  • factories might be a useful pattern for constructing instances of the various implementations - though possibly just constructors on various classes (new ArrayMatrix, new FileMatrix), or overloads (CreateMatrix(...), CreateMatrix(...,string filename)), or simply logic based on data (MakeMatrix(...,string backend) where backend is a filename, except that "array" or null maybe means something else) is enough
Brian
Is there a standard way to make the factory extensible. That is, how to third parities add their backends to the factory?
Tristan
Uhm, let's say no. :) This sounds like flirting with over-engineering; if you have an interface, then any third-party can implement the interface and clients can just call the third-party constructor, for example. A registry framework for third-parties to plug into the main factory is possible (every problem can be solved by adding a layer of indirection), but that's sounding pretty wonky for just some code to let F#/python scripts use matrices :)
Brian
@Tristan, @Brians: Brian's comment made me think of http://www.codinghorror.com/blog/archives/000113.html
Bruno Reis
Yes, a dangerous temptation.
Tristan