0
\$\begingroup\$

I'm writing a C# library that's a wrapper around the Yahoo Finance YQL API. I'm stuck on how I want to expose my API to consumers. My design thus far consists of separate interfaces for the different parts of the Yahoo Finance API:

public interface IYahooFinanceCharts {
 Task<Image> GetChartAsync(string tickerSymbol, ChartSize size, ChartTimeSpan timeSpan);
}
public interface IYahooFinanceQuotes {
 Task<IEnumerable<Quote>> GetQuotesAsync(params string[] tickerSymbols);
}
public interface IYahooFinanceStocks {
 Task<IEnumerable<Stock>> GetStocksAsync(params string[] tickerSymbols);
}
public interface IYahooFinanceTickerSymbols {
 Task<IEnumerable<TickerSymbol>> SearchAsync(string symbolOrKeyword);
}

I have internal classes that implement these interfaces to handle the details of building a request for the YQL API and parsing the result of the response. I don't want to expose these classes to consumers.

I was thinking of using a facade to reduce the main entry point into my API to one class. Consumers could cast, instantiate, or register (DI container) the facade using the various interfaces to zero-in on the parts they're interested in.

public class YahooFinance : IYahooFinanceCharts, IYahooFinanceQuotes, IYahooFinanceStocks, IYahooFinanceTickerSymbols
{
 // Delegating calls to the internal classes that implement these interfaces...
}
...
IYahooFinanceStocks stocks = new YahooFinance();
var results = await stocks.GetStocksAsync("MSFT", "GOOG");

I'm not sure if I like this because if consumers simply use

var yahooFinance = new YahooFinance();

the entire API is exposed to them, defeating the purpose of the separate interfaces. On the other hand, not using a facade and forcing consumers to instantiate the concrete class for each interface is clumsy, increases the surface area of the API, and I'd have to expose the concrete types...

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked May 20, 2014 at 4:04
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

What you're looking for is actually the factory pattern.

Your implementation could be something like

public class YahooFinanceFactory{
 public IYahooFinanceQuotes GetQuotes()
 {
 return new YahooFinanceQuotesConreteImplementation();
 }
[...]
}

The concrete implementations are still marked as internal so they are not exposed.

Alternatively, you could use reflection for this.

public static T ResolveConcreteType<T>()
{
 return (from t in Assembly.GetExecutingAssembly().GetTypes()
 where t.GetInterfaces().Contains(typeof(T))
 && t.IsClass //Find the classes that implement the interface we want
 select (T)Activator.CreateInstance(t, null))
 .SingleOrDefault();
}

Usage:

var quotes = YahooFinanceFactory.ResolveConcreteType<IYahooQuotes>();

This makes the assumption that your concrete types support empty constructors however.

answered May 20, 2014 at 13:48
\$\endgroup\$
1
  • \$\begingroup\$ My concretes types do have empty constructors so that's not a problem. My concern with this design is that it's duplicating the work of a DI container (i.e. resolving concrete types from interfaces) and is essentially a service locator. \$\endgroup\$ Commented May 20, 2014 at 22:04

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.