I'm facing a design challenge that I just can't seem to solve in a satisfactory way. I've got a class library assembly that contains all of my shared ORM objects (using EntitySpaces framework). These objects are used in 2 or more different applications which is why they are in their own assembly. This setup has worked fine for 4+ years for me.
I also have a couple of applications built on the Composite Application Block (CAB) from Microsoft's Patterns & Practices group (P&P). Yes, I know this is really old but I'm a part time developer, one-man-shop and can't afford to update to whatever the current framework is.
Here is where my problem comes in: I have been exercising my OO design skills and whenever doing a substantial refactoring I try to shift from a procedural approach to a more OO approach. Of course a major aspect of OO design is placing the operations close to the data they work with, this means tha开发者_Go百科t my ORM objects need to have functionality added to them where appropriate. This is proving a real head scratcher when I also consider that I'm using P&P's Object Builder DI container within CAB and that much of the functionality I would move into my ORM objects will need access to the services exposed by my applications.
In other words, let's say I have a shared business object called "Person" (original, I know) and I have two applications that do ENTIRELY different things with a person. Application A provides a set of services that the Person object would need to have DI'ed in order for it to take on some of the methods that are currently littered throughout my services layers. Application B also has a different set of services that IT needs to have DI'ed into the person object.
Considering how the P&P Object Builder resolves dependencies using attribute decoration and Type reflection I don't see how I can accomplish this. In a nutshell, I have a shared object that when used in various applications I would need to inject dependencies so that it can perform certain operations specific to that application.
The only approach I can come up with is to inherit a new Type in Application A & B from the Person object. I would then add my non-shared functionality and DI code into this application-specific specialized Person object. Now that I write that it seems so obvious, however it's still my only solution I can come up with and I wanted to ask here to see if anyone else had a different solution they would like to propose?
One problem I would have with my solution is that I can see myself getting caught up on naming my inherited type - I mean... it's a person, so what else would you call it? Anyways, hopefully you will have some ideas for me.
Also, I'm not hip on the current technologies that are out there and really, to be honest only barely grasp the ones I'm currently using. So if I've said something contradictory or confusing I hope you can understand enough from the rest of the post to get what I'm asking.
It sounds like you're breaking the Single Responsibility Principle.
A Person
object should just be holding the data for a person record. The services would then take in a Person
object and manipulate it rather than having methods on the Person
object that did that manipulation.
A classic example of this would be populating the Person
object. Lets say app A grabs the data from a WebService, and app B grabs it from a database. In these cases I'd have some sort of Storage
service that you call to get your Person
object. Then implementation of that storage can be specific to each application, and be put into your IOC by the app, rather than trying to have a common interface in your shared assembly.
I agree with Cameron MacFarland on this: You are breaking SRP.
Of course a major aspect of OO design is placing the operations close to the data they work with, this means that my ORM objects need to have functionality added to them where appropriate
Placing data AND functionality from A AND functionality from B is two responsibilities too much. Adhearing to SRP will almost always result in seperating data and functionality in seperate classes (data structures and objects). Thus, using Cameron MacFarlands sugestion is probably the best way to go.
I could think of couple of approaches to address this.
- Separate out the behavior specific to each person/application separately. Perform dependency injection using setter in the application itself.
Apporach1
public interface IPerson
{
IPersonApp1 Person1 {get; set;}
IPersonApp2 person2 {get; set;}
}
class Person : IPerson
{
IPerson1 Person1 {get; set;}
IPerson2 Person2 {get; set;}
}
public interface IPerson1
{
// App1 specific behavior here
void App1SpecificMethod1();
}
class Person1: IPerson1
{
void App1SpecificMethod1()
{
// implementation
}
}
class App1
{
IPerson objPerson;
// Dependency injection using framework
App1(IPerson objPerson)
{
this.objPerson = objPerson;
// Dependency injection using setter
this.objPerson.Person1 = new Person1();
}
}
- Separate out the behavior specific to each person/application separately. Perform dependency injection in the Person constructor.
Apporach2
class Person : IPerson
{
IPerson1 Person1 {get; private set;}
IPerson2 Person2 {get; private set;}
// DI through constructor. If the type IPerson1 or IPerson2 are not registered, it will be set to null.
Person(IPerson1 objPerson1, IPerson2 objPerson2)
{
this.Person1 = objPerson1;
this.Person2 = objPerson2;
}
}
Person interface project need to have reference to IPerson1 and IPerson2 or you can declare IPerson1 and IPerson2 in the Person interface project itself.
精彩评论