10

I have an interface ITradingApi like so:

public interface ITradingApi
{
    IOrder CreateOrder(...);
    IEnumerable<Symbol> GetAllSymbols();
    // ...
}

This is meant to be a facade for the different APIs of the vendors of trading software. My view model has a dependency on this trading API in its constructor:

public class MainViewModel
{
    public MainViewModel(ITradingApi tradingApi) { /* ... */ }
    // ...
}

I use Ninject as an IoC container, so I will create an instance of my view model like this:

var vm = kernel.Get<MainViewModel>();

Now, my problem:

The implementation of ITradingApi might need additional parameters to work.
Example:

  • One vendors API uses TCP/IP internally, so I need a hostname and a port.
  • Another vendor uses a COM object. Here I don't need any info.
  • A third vendor needs username and password of the account.

In the spirit of not allowing incomplete objects, I added these as parameters to the constructors of the concrete implementations.

Now, I am not sure, how this would work. Clearly, these additional parameters do not belong into the interface, because they are specific to each implementation.
On the other hand, these additional parameters need to be entered by the end-user and then passed to the implementation of ITradingApi, meaning that the user of ITradingApi needs intimate knowledge about the concrete implementation.
How to solve this dilemma?

UPDATE:
One approach could be to create an ITradingApiProvider that exposes a list of required parameters. The View could automatically create an input form for these parameters that is databound to the parameters in ITradingApiProvider. Now, when an ITradingApi instance is requested from the provider, it can make use of these parameters to create an instance of the concrete implementation. Clearly the implementation of ITradingApiProvider and ITradingApi are tightly coupled, but I think that is not a problem as long as each implementation of ITradingApi comes with a corresponding implementation of ITradingApiProvider.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • BTW: I read [this](http://stackoverflow.com/questions/1685531/constructor-injection-with-other-non-dependency-constructor-arguments) before posting, but I am unable to transfer it to my problem... – Daniel Hilgarth Jul 21 '11 at 07:26
  • Have you thought about using the [visitor pattern](http://en.wikipedia.org/wiki/Visitor_pattern)? It looks to me this Api might be used like the car of the example. – Arthis Jul 21 '11 at 07:53
  • @Yoann: Thanks for your suggestion. Could you please elaborate a bit? I am unable to see, how the visitor pattern could by used in my scenario. – Daniel Hilgarth Jul 21 '11 at 08:09
  • I just found [this](http://stackoverflow.com/questions/1943576/is-there-a-pattern-for-initializing-objects-created-via-a-di-container/1945023#1945023) answer. This shows that my approach using `ITradingApiProvider` is the way to go. The only difference would be, that my `ITradingApiProvider` would be a little bit more complex, because of the fact that the number and types of the needed parameters is unknown. – Daniel Hilgarth Jul 21 '11 at 09:06
  • Does the *user* really need to enter those values? They sound more like configuration values to me. If so, they can be resolved at composition time. – Mark Seemann Jul 21 '11 at 14:57
  • @Mark: I really hoped you would drop by here ;-) It depends a little bit on what you mean when you say "configuration values". As with the example of username and password (third vendor), this is something each user has to enter individually - be it in the UI in a configuration dialog or directly in some configuration file. Taking it a step further: Imagine an application that let's the user choose at runtime which implementation of the API he wants to use, basically allowing him to choose between different trading possibilities. Vendor 1 might only allow Forex trading, vendor (cont.) – Daniel Hilgarth Jul 21 '11 at 15:34
  • (cont.) two might only allow stock trading. And in the next step, the user might choose which of his three stock trading accounts he wants to use. So in my opinion, the user needs to enter this data at least at some point in time. Maybe it is clearer for me, when you explain how resolving these parameters at composition time works, when they are "configuration values". BTW: I also posted an [answer](http://stackoverflow.com/questions/6772636/constructor-injection-with-non-dependency-parameters/6773891#6773891) to this question, you might want to read it and comment on it. – Daniel Hilgarth Jul 21 '11 at 15:34

6 Answers6

3

Based on the information so far put forth here, I'd like to point out one or two things:

First of all, whether or not the concrete configuration values are supplied at composition time or truly first available at runtime as user input makes a huge difference. As long as they can be resolved at composition time things are easy because you can simply read the values from the environment and supply them to the appropriate constructors. So, for the rest of this answer I'm going to assume that things are much harder and you actually need to get those values from the user at runtime.

Instead of attempting to come up with a general-purpose configuration API I'd much rather model what's actually going on. In this case it sounds to me like we're collecting configuration values from the user, so why not model this explicitly?

Product Trader

Define an interface like this:

public interface ITradingApiTrader
{
    ITradingApi Create(Type apiType);
}

Here, it's assumed that apiType can cast to ITradingApi, but this can't be enforced by the compiler. (The reason I'm calling this a 'Trader' is because this is a variation of the Product Trader pattern (PLoPD 3).)

How is this different than before?

Well, you can implement the Create method by showing a user interface for each type of ITradingApi. Each concrete user interface gathers the values required for its own concrete ITradingApi implementation and subsequently returns a correctly configured instance.

If you know the concrete types at compile time, other variations include these:

public interface ITradingApiTrader
{
    ITradingApi CreateMT4TradingApi();

    ITradingApi CreateFooTradingApi();

    ITradingApi CreateBarTradingApi();

    // etc.
}

Perhaps you can also do this (although I haven't tried to compile this):

public interface ITradingApiTrader
{
    ITradingApi Create<T>() where T : ITradingApi;
}

Note also that you don't need to define the first ITradingApiTrader's Create method based on a Type - any identifier (such as an enum or string) might do instead.

Visitor

If the set of ITradingApi is (finite and) known at design time, the Visitor design pattern might also offer an alternative.

If you use a Visitor, you can make the Visit method show an appropriate user interface and then subsequently use the values collected from the user interface to create the appropriate ITradingApi instance.

Basically this is just a variation on the previous 'solution' where the Product Trader is implemented as a Visitor.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • Thanks for your input. About the first part of the answer: If the values are known at composition time, I still would need an `ITradingApiFactory`, right? But each concrete implementation then could simply read the data from the configuration file and create the instance of `ITradingApi` with this data. Is that what you are saying? In that case, the factory is basically *asking* about the values, they are not being *told* to it. Isn't this a violation of the Hollywood principle? (I will comment about the rest of your answer, as soon as I have understood it) – Daniel Hilgarth Jul 21 '11 at 18:34
  • No, if you know the values at composition time you don't need an `ITradingApiFactory`. In that case you just pass the values directly to the constructors in question, because that's what you do when you compose an object graph. – Mark Seemann Jul 21 '11 at 21:02
  • Sorry, I don't understand that. How would that work when resolving `MainViewModel` which requires an instance of `ITradingApi` (see code in question)? Where would I pass the constructor parameters? Remember, the following requirement still stands: It is unknown which implementation needs which parameters. The user could simply drop another DLL into the bin folder with a different implementation of the interface and other ctor parameters. So even if the parameters are known at composition time, they are **not** known by the composition root, because they are implementation specific. – Daniel Hilgarth Jul 22 '11 at 07:52
  • 1
    Logically that sounds like a circular dependency. Modeling-wise that sounds wrong: if you first need to query the user about the configuration values of a selected ITradingApi, it doesn't make sense to also make it a dependency of MainViewModel. Assuming that MainViewModel is the root, it sounds like it should rather depend on ITradingApiTrader. This would allow you to pop up a dialog asking the user to select an ITradingApi from a list, which would then show the dialog. Alternatively, this flow could be placed entirely before the MainViewModel is created - essentially like a login screen. – Mark Seemann Jul 22 '11 at 08:07
2

Is this what your after?

   ninjectKernel.Get<MainViewModel>().WithConstructorArgument("tradingApi", 
       kernel.Get<ITaxCalculator>() .WithConstructorArgument("additionalParameter","someValue")));
Razor
  • 17,271
  • 25
  • 91
  • 138
  • Thanks for your answer, but no. That would exactly require that intimate knowledge of the concrete implementation of `ITradingApi` I don't want to have. – Daniel Hilgarth Jul 21 '11 at 07:37
  • 1
    You could have a method for the ITradingApi interface that allows you to set additional parameters. ITradingApi.SetAdditionalValues(IEnumerable entries); – Razor Jul 21 '11 at 07:42
  • I just updated my question. This is similar to your suggestion, but IMHO a little bit cleaner, because it separates the concerns. What do you think? – Daniel Hilgarth Jul 21 '11 at 07:44
  • 1
    Your suggestion is definitely a better approach. – Razor Jul 21 '11 at 07:50
  • Thanks! Could you please update your answer with your suggestion about SetAdditionalValues? I upvoted you answer, but I really don't like the part with WithConstructorArgument. I upvoted because of your first comment... – Daniel Hilgarth Jul 21 '11 at 08:38
1

Ok my two cents, I am not sure of anything you know. It is just to help and try...

We give a visitor to your api as construction of the interface:

public interface ITradingApi
{
    Object CreateOrder();
    IEnumerable<Object> GetAllSymbols();
}

public class TradingApi : ITradingApi
{
    IvisitorAPI _VisitorAPI;

    public TradingApi(IvisitorAPI visitorAPI)
    {
        _VisitorAPI = visitorAPI;
    }


    public Object CreateOrder()
    {
        var Order = new Object();
        //bla bla bla

        //here code relative to different visitor
        _VisitorAPI.SaveOrder(Order);

        return Order;
    }
}

It is your visitor that knows how to handle some of the action, because depending on the visitor he will use your api in different ways to achieve the same action ( here SaveOrder).

public interface IvisitorAPI
{
    bool SaveOrder(Object order);
}



public class visitorApiIP : IvisitorAPI
{
    public string HostName { get; set; }
    public int Port { get; set; }

    public visitorApiIP(string hostname, int port)
    {
        HostName = hostname;
        Port = port;
    }


    public bool SaveOrder(Object order)
    {
        //save the order using hostname and ip
        //...
        //....
        return true;
    }
}

Only the visitor has a knowledge of what he needs to achieve his version of the action. Therefore it is not the APi that needs additionnal parameters, we are pushing the logic away in the visitor class. This visitor class might be created only when ewe know who is the visitor therefore, surely at runtime

Hope it might give you some perspective. I do not know if the whole theory can be applied your exact situation.

My best anyway ;)

Arthis
  • 2,283
  • 21
  • 32
  • Thanks for elaborating. But this really just inserts an additional indirection. Now I have exactly the same problem with the construction of an instance of `IvisitorAPI`. – Daniel Hilgarth Jul 21 '11 at 08:25
  • I am surely missing something then, because at runtime, you tell the correct IvisitorAPI you need in Ninject, and then when Ninject instanciates the API, he will know what to do. – Arthis Jul 21 '11 at 08:30
  • You are right this is basically the same thing. The only difference is making your API interface a bit cleaner., perahps too much code only for this. Sorry for the input. – Arthis Jul 21 '11 at 08:34
  • Yes, you are missing something. Think about a second implementation of `IvisitorAPI` called `visitorApiSecure`. It has a constructor with 4 arguments: `hostname`, `port`, `username`, `password`. I only know about these constructor parameters if I use the concrete type rather than the interface, which defeats the purpose of the interface in the first place. That's exactly the problem I described in my question. – Daniel Hilgarth Jul 21 '11 at 08:35
  • aren't you trying to recreate Bind().ToProvider(myclass)? see [here](http://www.kevinrohrbaugh.com/blog/2009/8/7/using-ninject-2-with-aspnet-mvc.html) for an example. – Arthis Jul 21 '11 at 10:26
  • That's why I called it `ITradingApi` **`Provider`** in the first place :-) I first thought, I could use this, but I really can't, because I need the provider itself in the ViewModel to be able to create the UI for the parameters. Please see [my answer](http://stackoverflow.com/questions/6772636/constructor-injection-with-non-dependency-parameters/6773891#6773891) for more info. – Daniel Hilgarth Jul 21 '11 at 11:47
1

The solution is to use the approach as outlined in the update part of my question. ITradingApiProvider takes the role of an abstract factory and thus should be renamed to ITradingApiFactory. It would expose a list of needed parameters whose values can be set. This list in turn can be used by the View to automatically present the user with an input form to enter a value for each parameter, because only the user knows the values of for the parameters.
The call to Create would then use these parameters:

public interface ITradingApiFactory
{
    ITradingApi Create();
    IEnumerable<Parameter> Parameters { get; }
}

public class Parameter
{
    public Parameter(Type type, string name, string description)
    { Type = type; Name = name; Description = description; }

    public Type Type { get; private set; }
    public string Name { get; private set; }
    public string Description { get; private set; }
    public object Value { get; set; }
}

public class MT4TradingApiFactory : ITradingApiFactory
{
    Dictionary<string, Parameter> _parameters;

    public MT4TradingApiFactory()
    { /* init _parameters */ }

    public ITradingApi Create()
    {
        return new MT4TradingApi(_parameters["hostname"].ToString(),
                                 (int)_parameters["port"]);
    }

    IEnumerable<Parameter> Parameters { get { return _parameters.Values; } }
}

More info can be found in this answer.

This can be advanced further to make it easier to use, by giving each Factory implementation the parameters as properties and change the Parameter class to work directly on these properties using expression trees. If someone is interested in this advanced factory design, please leave a comment.

Community
  • 1
  • 1
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
1

I think there is nothing wrong with your provider approach. You have two concerns here:

  1. An operational one: your ITradingAPI which defines a contract for operations you can perform.
  2. A meta-data one: something which describes properties of an actual implementation (meta data might not be quiet right but can't think of a better name for it)

Now apparently you need something which can make the connection between the two and that is your ITradingAPIProvider. Seems reasonable straight forward and has good chance of that you will still understand your code when coming back to it after a year ot two ;)

ChrisWue
  • 18,612
  • 4
  • 58
  • 83
0

How about trying something similar to the strategy pattern? Create a new interface called IConnectStrategy:

interface IConnectStrategy
{
    void Connect();
}

Add the connectstrategy as an argument to the method void CreateOrder(IConnectStrategy connectStrategy) in ITradingApi and let each vendor create/specify their own method for connecting. E.g. for one vendor create:

public class TCPConnectStrategy : IConnectStrategy
{
    public TCPConnectStrategy(string hostName, int port)
    {
        /* ... */
    }

    public void Connect()
    {
        /* ... tcp connect ... */
    }
}

(Connect might not be the best name or even what you are actually doing, but please apply it to whatever works for your project.)

Edit after comments: Create a strategy that only have contracts for each method that have vendor-specific parameters. Then add a method void SetVendorStrategy(IVendorStrategy vendorStrategy) (or a property) to the ITradingAPI-interface. Each implementation of the strategy has their own constructor with their own parameters, and each method (that require vendor specific parameters) in each implementation of the ITradingAPI-interface simply calls vendorStrategy.DoSomethingWithVendorSpecificData().

Andreas Ågren
  • 3,879
  • 24
  • 33
  • Thanks for the suggestion. However, this doesn't work in my scenario, because the implementation of `CreateOrder` is completely different for different vendor APIs used. For example for MetaTrader4 it would be something like `metatraderApi.OrderSend(symbol, price, ...)` and for another vendor API it would be `vendorApi.Orders.CreateNewOrder(price, symbol, ...)`. They have absolutely nothing in common... – Daniel Hilgarth Jul 21 '11 at 08:32
  • @Daniel, then instead of having a connectstrategy, have a createorderstrategy-interface which only exposes a method `void CreateOrder()`. Then in `MainViewModel` take this strategy in the constructor, or via ITradingAPI. (After your comment I'm unsure what your current design looks like since it seems you have several different ITradingAPI-interfaces?) – Andreas Ågren Jul 21 '11 at 08:42
  • No, there is only one `ITradingApi` interface but several different implementations of it. Your suggestion basically means, that I need one strategy per method that is exposed by the interface. One for `CreateOrder`, one for `GetSymbols` and so on for all the 20 or so other methods... This further means that the functionality of one implementation of `ITradingApi` is spread all over the place, one little piece in each strategy. – Daniel Hilgarth Jul 21 '11 at 08:47
  • @Daniel, it would be enough with one strategy, see the edit in my answer. – Andreas Ågren Jul 21 '11 at 09:16
  • This is not usable in my context, I am sorry, because it still doesn't solve the problem with the unknown types and number of parameters. Please see my answer to this question. – Daniel Hilgarth Jul 21 '11 at 09:24
  • @Daniel So the number of-/type of parameters for each method is unknown until runtime? Sorry but to me that was not entirely clear in your question. – Andreas Ågren Jul 21 '11 at 09:38
  • Not for each method. But for the initialization of the vendor API. Sorry if my question was not clear... – Daniel Hilgarth Jul 21 '11 at 09:39
  • My example is analogous to the following: Think about the abstract Stream class as of `ITradingApi` and `FileStream` and `MemoryStream` as concrete implementations of `ITradingApi`. After `FileStream` or `MemoryStream` are constructed, you can use them independent of the current type. But the initialization is different: One needs a filename and the other needs a byte array. – Daniel Hilgarth Jul 21 '11 at 09:43