It seems you're struggling trying to create objects that create objects... wouldn't you be better off just creating objects ?
Ninject allows you to do so in a very simple way :
// Ninject module
Bind<IRepository<SomeEntity>>().To<SomeEntityRepository>();
// injected class
public class SomeService
{
public SomeService(IRepository<SomeEntity> repository)
{
// ...
}
}
// get instance of injected class
var someService = kernel.Get<SomeService>();
I can't see the benefit of an abstract factory in addition to an IoC container when you're creating objects based on basic, compile-time-known constraints such as in your SomeViewFactory
and SomeRepositoryFactory
examples.
The dynamic nature of SomeFunctionalityFactory
would be more debatable, but when you think of it, do you really need to instantiate an object with the built-in notion that it will never be able to be used by the current user ? Wouldn't it make more sense to have the object evaluate user authorization when the functionality is called ?
How large is your application? There's a good chance you're overthinking this. Unless the application is a large, enterprise-grade application, the high degree of loose coupling you are advocating is probably unnecessary.
If you decide that this level of loose coupling is still necessary, create a service layer that returns "service" objects. This fulfills a similar function to View Models in MVC. You will then write code in your service layer that maps objects from your domain model to your service model.
Note that part of your struggle may be due to the fact that, while your Data Repository is returning CRUD objects, your Service Layer should be returning the result of actions. For example:
public InvoiceView GetInvoice(int invoiceID);
returns a InvoiceView
object containing whatever data you wish to expose to the public, including Name, Address, Line Items and so forth, from several different tables/objects in your domain.
public class InvoiceView
{
public int InvoiceID;
public Address ShippingAddress;
public Address BillingAddress;
public List<LineItem> LineItems;
...
}
Similarly, there will be Service Layer methods that simply performs an action and returns an object indicating the result of the action:
public TransactionResult Transfer(
int sourceAccountID, int targetAccountID, Money amount, ValidationToken token);
IMPORTANT: You'll never be able to completely decouple from your data. Your consumer will always have to have some knowledge of the data, even if it's just an object ID or UUID.
Best Answer
The main reason you would have the interfaces for your repositories in your BLL is to avoid having hard references to the separate DAL but instead have your changing DAL reference the stable BLL.
To be able to swap out implementations without changing the stable BLL
On the internet this might not be the main reason in general, but this would be a compelling reason for me to prefer option 2 in your situation.
Let's assume that you are using a DI (dependency injection) container. If you configure this using a configuration file, for example, you would tell the container that the implementations for the repository-interfaces in the BLL can be found in the DAL.Sql project. Once you switch over to a NoSQL solution you would create the DAL.NoSQL project, deploy it and change the DI container configuration to resolve the implementations of the repository from the new project. Your new DAL depends on the stable BLL that does not need to change.
However, if you go with option 1, you might not be able to hot-swap the DAL project. If you use .NET for example you could run into issues where the BLL project depends on a certain version of the DAL dll and you would not be able to swap out the DAL without changing the BLL as well.
Because the repository interface is part of the BLL
A repository is merely a gateway that defines how your application will retrieve data. In that sense it is as much a part of the business logic as your domain objects. The concrete implementations can change, but the interfaces themselves are part of your business logic.
Because it isolates the BLL
Having the interfaces and implementations in the DAL means bringing all of the DAL into the BLL. There is nothing preventing developers from using objects from the DAL project in ways that they shouldn't be used. Having the DAL depend on the BLL means the BLL can only contain the interfaces that it needs.
To avoid a separate project with the domain objects
Your DAL and BLL both depend on your domain objects. If your BLL has a class that uses a repository and a domain object, you cannot put your repository interfaces into the DAL as that creates a circular reference (BLL needs interface for repository in DAL, DAL needs domain objects in BLL). So you would have to split the BLL and the domain objects into two projects so your BLL can reference the domain and the DAL and the DAL can also reference the domain.