I am looking for an elegant design for a problem analogous to the following:
A story can have a flexible hierarchical structure. It might consist of several books, each of which have chapters, each of which have sections, each of which contain text. Or, it might simply have sections (a short story for instance). Or it might just consist of chapters that have sections. In all situations, you mustn't be allowed to mix styles (so you couldn't add a chapter to a story based on books, you would have to add the chapter to the book itself).
I have come up with a couple of design solutions for this type of problem but they get messy. Is there a clean way to represent this so that, given a reference to a Story class I can get access to the content in a clear, systematic fashion?
Its kind of tricky situation because the concepts like "Books", "chapters", "sections", may have some common elements that suggest a class hierarchy or common interface implementation.
And at the same time, enough different to be handle as different classes / objects, at all, as the requirement of "so you couldn't add a chapter to a story based on books".
When dealing conceptualy with hierarchical objects, there are several approaches of how to turn them into into code, each one suits better to a particular situation.
1. Class Composition
There is a class or prototype for each concept, they may be related or not by inheritance or interfaces.
There are internal collections of the elements, and their operations can be restricted,
by methods.
// this one can be optional, not required,
// replaced by several parent classes,
// or replaced by interfaces
public class LibraryRootClassMaybe {
// members here
}
public class BookText extends LibraryRootClassMaybe {
// members here
} // class BookText
public class BookSection extends LibraryRootClassMaybe {
// element collection should not be public
List BookTexts;
public Book() {
this.BookTexts = new ArrayList();
}
public void addBookTest(BookText Item) {
// validation and casting from object to BookText
}
// members here
} // class BookSection
public class BookChapter extends LibraryRootClassMaybe {
// element collection should not be public
List BookSections;
public Book() {
this.BookSections = new ArrayList();
}
public void addBookTest(BookSection Item) {
// validation and casting from object to BookSection
}
// members here
} // class BookChapter
public class Book extends LibraryRootClassMaybe {
// element collection should not be public
List BookChapters;
public Book() {
this.BookChapters = new ArrayList();
}
public void addBookTest(BookText Item) {
// validation and casting from object to BookText
}
// members here
} // class Book
These approach is good when there are not many different classes, maybe 5.
2. The Tree Design Pattern.
These one applies when all elements will be equal if not similar,
usually same class or interface, usually a lot of items.
These one does not apply to your case, but,
I had to mention, to apply better.
Usually, a tree / hierarchical collection class, its used.
It could be a subclass of a generic / template tree collection,
or a subclass of a base tre collection,
that is intended to be replaced by child classes with particular members.
public class FileSystemRootClass {
public bool AmISystemRoot() {
// more
}
public bool AmIAFolder() {
// more
}
public bool AmIAFile() {
// more
}
public void addSystemRoot(string FileSystemName) {
// more
}
public void addFolder(string FileSystemName) {
// more
}
public void addFile(string FileSystemName) {
// more
}
// members here
}
3. The Hybrid.
These one is a combination of the previous two,
its used when there is a lot of related items,
its more complex, may use or not the Factory & Abstract Factory Patterns,
and its more common example are visual controls & widgets libraries.
import java.util.*;
public class WidgetsExample {
public static void main(String[] args) {
TreeSet <Widget> FormControls = new TreeSet<Widget>();
TextBoxWidget TextBox = new TextBoxWidget();
FormControls.add(TextBoxWidget);
ListBoxWidget ListBox = new ListBoxWidget();
FormControls.add(TextBoxWidget);
ButtonWidget Button = new ButtonWidget();
FormControls.add(Button);
} // class WidgetsExample
You may notice that I didn't use the "factory pattern" & "abstract factory",
due to require more code.
Good Luck.
Good OO design starts with thinking about Use Cases and not class hierarchies. This is a common mistake and tends to produce over-complicated designs.
First consider what you are building and write out a problem statement a description of the problem you are solving using English prose in the language of the problem domain.
Then consider making a mockup if the product is a UI.
Then you can start writing out use cases and start thinking about how objects will interact with each other.
It's called Object-oriented programming, not Class-oriented programming. Classes are the specification in code to manage/create/run all the objects in the system. I'd be thinking about objects and what they are doing. Classes are simply an implementation detail.
If your goal is to perform operations on hierarchies, you might want to consider using the Composite pattern. You could do something like have a Story object that can contain a list of Story objects. Each Story object would also have it's own type (book-collection,book,chapter,sub-chapter,paragraph,essay), and it's own attributes and methods (depending on your use cases).
I'd try something like this:
interface StoryElement<SE extends SubElements>{
List<SE> getContents()
}
class Story<T extends StoryElement>
class Book implements StoryElement<Chapter> ...
class Chapter implements StoryElement<Section> ...
class Section implements StoryElement<Text>
class Text implements StoryElement<Text> {... // ugly hack, don't know of a clean way to end the recursion with Java Generics
Now you can have a Story of Books or a Story of Text.
Warning: Java Generics tend to fall flat on their face when trying to complex things. In case of doubt, just forget generics and cast.
Thanks to all the posters. Here is my work-in-progress solution:
public abstract class Element
{
public ElementSet getContent() { return content; }
// Overrides of setContent() check to see if the content type is appropriate
// using instanceof.
public void setContent( ElementSet content )
{
this.content = content;
}
private ElementSet content;
}
public abstract class ElementSet
{
protected final void addElement( Element e )
{
elements.add(e);
}
private final List<Element> elements = new ArrayList<Element>();
}
public class BookSet extends ElementSet
{
// Typesafe interface.
public void addBook( Book book ) { super.addElement( book ); }
}
public class ChapterSet extends ElementSet { /* similar to BookSet */ }
public class SectionSet extends ElementSet { /* similar to BookSet */ }
public class Book extends Element
{
#Override
public void setContent( ElementSet content )
{
if ( !(content instanceof ChapterSet) && !(content instanceof SectionSet) )
{
throw new RuntimeException();
}
super.setContent( content );
}
public boolean addChapter( Chapter chapter )
{
ElementSet content = getContent();
if ( content == null )
{
content = new ChapterSet();
setContent( content );
}
else if ( !(content instanceof ChapterSet) )
{
// Structure is wrong.
return false;
}
ChapterSet chapters = (ChapterSet)content;
chapters.addChapter( chapter);
return true;
}
public boolean addSection( Section section )
{
ElementSet content = getContent();
if ( content == null )
{
content = new SectionSet();
super.setContent( content );
}
else if ( !(content instanceof SectionSet) )
{
// Structure is wrong.
return false;
}
SectionSet sections = (SectionSet)content;
sections.addSection( section );
return true;
}
}
public class Chapter extends Element
{
#Override
public void setContent( ElementSet content )
{
if ( !(content instanceof SectionSet) )
{
throw new RuntimeException();
}
super.setContent( content );
}
public boolean addSection( Section section )
{
ElementSet content = getContent();
if ( content == null )
{
content = new SectionSet();
super.setContent( content );
}
else if ( !(content instanceof SectionSet) )
{
// Structure is wrong.
return false;
}
SectionSet sections = (SectionSet)content;
sections.addSection( section );
return true;
}
}
I tried using generics to achieve the same end, but it looked rather ugly due to need to reflect the parametrised type of a container.
Related
Suppose I have a game, where there are buildings sorted by type. Each type is represented as a separate class, but sometimes I have to do some uncommon logic for the buildings of the same type. How could one implement this kind of behaviour?
For example, I can identify buildings by ID, so I can have a giant switch or command pattern inside the building type class. But I think that something is not right with this approach.
Another approach is to have different class for any divergent logic. But this proposes a lot of small classes.
This is what polymorphism aims to solve, and one of the big differences between procedural and oop programming. You can achieve it through extending a base class, or by implementing an interface. Here is extending a base class:
public abstract class Building {
abstract void destroy();
}
public BrickBuilding extends Building {
#Override
public void destroy() {
bricks.fallToGround();
}
}
public HayBuilding extends Building {
#Override
public void destroy() {
straw.blowInWind();
}
}
In places in your code where you would have used a switch statement to switch on building type, just hold a reference to the abstract Building type, and call method destroy() on it:
public class BuildingDestroyer {
public void rampage() {
for(Building building : allTheBuildings) {
// Could be a BrickBuilding, or a HayBuilding
building.destroy();
}
}
}
Or, to address your concern about having a lot of small types, you can 'inject' a destroy behaviour you want into a common building type, like so...albeing, you will end up with a lot of different destroy behaviour classes too...so, this might not be a solution.
public interface DestroyBehaviour {
void destroy(Building building);
}
public class Building {
private int id;
public DestroyBehaviour destroyBehaviour;
public Building(int id, DestroyBehaviour destroyBehaviour) {
this.id = id;
this.destroyBehaviour = destroyBehaviour;
}
public void destroy() {
destroyBehaviour.destroy(this); // or something along those lines;
}
}
You can get rid of the giant switch by having a BuildingFactory class which exposes a registerBuildingType(typeName, instanceCreatorFunc) method, that each building class calls (from a static initialize method for example) and that gets called with a unique string for that class (class name would suffice) and a static "create" method that returns a new instance.
This approach also has the advantage of being able to load new buildings from dynamically linked libraries.
I have spent the last day trying to work out which pattern best fits my specific scenario and I have been tossing up between the State Pattern & Strategy pattern. When I read examples on the Internet it makes perfect sense... but it's another skill trying to actually apply it to your own problem. I will describe my scenario and the problem I am facing and hopefully someone can point me in the right direction.
Problem: I have a base object that has different synchronization states: i.e. Latest, Old, Never Published, Unpublished etc. Now depending on what state the object is in the behaviour is different, for example you cannot get the latest version for a base object that has never been published. At this point it seems the State design pattern is best suited... so I have implemented it and now each state has methods such as CanGetLatestVersion, GetLatestVersion, CanPublish, Publish etc.
It all seems good at this point. But lets say you have 10 different child objects that derive from the base class... my solution is broken because when the "publish" method is executed for each state it needs properties in the child object to actually carry out the operation but each state only has a reference to the base object. I have just spent some time creating a sample project illustrating my problem in C#.
public class BaseDocument
{
private IDocumentState _documentState;
public BaseDocument(IDocumentState documentState)
{
_documentState = documentState;
}
public bool CanGetLatestVersion()
{
return _documentState.CanGetLatestVersion(this);
}
public void GetLatestVersion()
{
if(CanGetLatestVersion())
_documentState.CanGetLatestVersion(this);
}
public bool CanPublish()
{
return _documentState.CanPublish(this);
}
public void Publish()
{
if (CanPublish())
_documentState.Publish(this);
}
internal void Change(IDocumentState documentState)
{
_documentState = documentState;
}
}
public class DocumentSubtype1 : BaseDocument
{
public string NeedThisData { get; set; }
}
public class DocumentSubtype2 : BaseDocument
{
public string NeedThisData1 { get; set; }
public string NeedThisData2 { get; set; }
}
public interface IDocumentState
{
bool CanGetLatestVersion(BaseDocument baseDocument);
void GetLatestVersion(BaseDocument baseDocument);
bool CanPublish(BaseDocument baseDocument);
bool Publish(BaseDocument baseDocument);
SynchronizationStatus Status { get; set; }
}
public class LatestState : IDocumentState
{
public bool CanGetLatestVersion(BaseDocument baseDocument)
{
return false;
}
public void GetLatestVersion(BaseDocument baseDocument)
{
throw new Exception();
}
public bool CanPublish(BaseDocument baseDocument)
{
return true;
}
public bool Publish(BaseDocument baseDocument)
{
//ISSUE HERE... I need to access the properties in the the DocumentSubtype1 or DocumentSubType2 class.
}
public SynchronizationStatus Status
{
get
{
return SynchronizationStatus.LatestState;
}
}
}
public enum SynchronizationStatus
{
NeverPublishedState,
LatestState,
OldState,
UnpublishedChangesState,
NoSynchronizationState
}
I then thought about implementing the state for each child object... which would work but I would need to create 50 classes i.e. (10 children x 5 different states) and that just seems absolute crazy... hence why I am here !
Any help would be greatly appreciated. If it is confusing please let me know so I can clarify!
Cheers
Let's rethink this, entirely.
1) You have a local 'Handle', to some data which you don't really own. (Some of it is stored, or published, elsewhere).
2) Maybe the Handle, is what we called the 'State' before -- a simple common API, without the implementation details.
3) Rather than 'CanPublish', 'GetLatestVersion' delegating from the BaseDocument to State -- it sounds like the Handle should delegate, to the specific DocumentStorage implementation.
4) When representing external States or Storage Locations, use of a separate object is ideal for encapsulating the New/Existent/Deletion state & identifier, in that storage location.
5) I'm not sure if 'Versions' is part of 'Published Location'; or if they're two independent storage locations. Our handle needs a 'Storage State' representation for each independent location, which it will store to/from.
For example:
Handle
- has 1 LocalCopy with states (LOADED, NOT_LOADED)
- has 1 PublicationLocation with Remote URL and states (NEW, EXIST, UPDATE, DELETE)
Handle.getVersions() then delegates to PublicationLocation.
Handle.getCurrent() loads a LocalCopy (cached), from PublicationLocation.
Handle.setCurrent() sets a LocalCopy and sets Publication state to UPDATE.
(or executes the update immediately, whichever.)
Remote Storage Locations/ Transports can be subtyped for different methods of accessing, or LocalCopy/ Document can be subtyped for different types of content.
THIS, I AM PRETTY SURE, IS THE MORE CORRECT SOLUTION.
[Previously] Keep 'State' somewhat separate from your 'Document' object (let's call it Document, since we need to call it something -- and you didn't specify.)
Build your heirarchy from BaseDocument down, have a BaseDocument.State member, and create the State objects with a reference to their Document instance -- so they have access to & can work with the details.
Essentially:
BaseDocument <--friend--> State
Document subtypes inherit from BaseDocument.
protected methods & members in Document heirarchy, enable State to do whatever it needs to.
Hope this helps.
Many design patterns can be used to this kind of architecture problem. It is unfortunate that you do not give the example of how you do the publish. However, I will state some of the good designs:
Put the additional parameters to the base document and make it
nullable. If not used in a document, then it is null. Otherwise, it
has value. You won't need inheritance here.
Do not put the Publish method to the DocumentState, put in the
BaseDocument instead. Logically, the Publish method must be part
of BaseDocument instead of the DocumentState.
Let other service class to handle the Publishing (publisher
service). You can achieve it by using abstract factory pattern. This
way, you need to create 1:1 document : publisher object. It may be
much, but you has a freedom to modify each document's publisher.
public interface IPublisher<T> where T : BaseDocument
{
bool Publish(T document);
}
public interface IPublisherFactory
{
bool Publish(BaseDocument document);
}
public class PublisherFactory : IPublisherFactory
{
public PublisherFactory(
IPublisher<BaseDocument> basePublisher
, IPublisher<SubDocument1> sub1Publisher)
{
this.sub1Publisher = sub1Publisher;
this.basePublisher = basePublisher;
}
IPublisher<BaseDocument> basePublisher;
IPublisher<SubDocument1> sub1Publisher;
public bool Publish(BaseDocument document)
{
if(document is SubDocument1)
{
return sub1Publisher.Publish((SubDocument1)document);
}
else if (document is BaseDocument)
{
return basePublisher.Publish(document);
}
return false;
}
}
public class LatestState : IDocumentState
{
public LatestState(IPublisherFactory factory)
{
this.factory = factory;
}
IPublisherFactory factory;
public bool Publish(BaseDocument baseDocument)
{
factory.Publish(baseDocument);
}
}
Use Composition over inheritance. You design each interface to each state, then compose it in the document. In summary, you can has 5 CanGetLatestVersion and other composition class, but 10 publisher composition class.
More advancedly and based on the repository you use, maybe you can use Visitor pattern. This way, you can has a freedom to modify each publishing methods. It is similiar to my point 3, except it being declared in one class. For example:
public class BaseDocument
{
}
public class SubDocument1 : BaseDocument
{
}
public class DocumentPublisher
{
public void Publish(BaseDocument document)
{
}
public void Publish(SubDocument1 document)
{
// do the prerequisite
Publish((BaseDocument)document);
// do the postrequisite
}
}
There may be other designs available but it is dependent to how you access your repository.
I have an object: X, that can be saved or loaded in various formats: TXT, PDF, HTML, etc..
What is the best way to manage this situation? Add a pair of method to X for each format, create a new Class for each format, or exists (as I trust) a better solution?
I'd choose the strategy pattern. For example:
interface XStartegy {
X load();
void save(X x);
}
class TxtStrategy implements XStartegy {
//...implementation...
}
class PdfStrategy implements XStartegy {
//...implementation...
}
class HtmlStrategy implements XStartegy {
//...implementation...
}
class XContext {
private XStartegy strategy;
public XContext(XStartegy strategy) {
this.strategy = strategy;
}
public X load() {
return strategy.load();
}
public void save(X x) {
strategy.save(x);
}
}
I agree with #DarthVader , though in Java you'd better write
public class XDocument implements IDocument { ...
You could also use an abstract class, if much behavior is common to the documents, and in the common methods of base class call an abstract save(), which is only implemented in the subclasses.
I would go with Factory pattern. It looks like you can use inheritance/polymorphism with generics. You can even do dependency injection if you go with the similar design as follows.
public interface IDocument
{
void Save();
}
public class Document : IDocument
{
}
public class PdfDocument: IDocument
{
public void Save(){//...}
}
public class TxtDocument: IDocument
{
public void Save(){//...}
}
public class HtmlDocument : IDocument
{
public void Save(){//...}
}
then in another class you can do this:
public void SaveDocument(T document) where T : IDocument
{
document.save();
}
It depends on your objects, but it is possible, that visitor pattern (http://en.wikipedia.org/wiki/Visitor_pattern) can be used here.
There are different visitors (PDFVisitor, HHTMLVisitor etc) that knows how to serialize parts of your objects that they visit.
I would instead suggest the Strategy pattern. You're always saving and restoring, the only difference is how you do it (your strategy). So you have save() and restore() methods that defer to various FormatStrategy objects you can plug and play with at run time.
I wonder how to add state to the chain of decorators that will be available to the consumer. Given this simplified model:
abstract class AbstractPizza
{
public abstract print(...);
}
class Pizza : AbstractPizza
{
public int Size { get; set; }
public print(...);
}
abstract class AbstractPizzaDecorator
{
public Pizza:AbstractPizza;
public abstract print();
}
class HotPizzaDecorator : AbstractPizzaDecorator
{
public int Hotness { get; set; }
public print(...);
}
class CheesyPizzaDecorator : AbstractPizzaDecorator
{
public string Cheese { get; set; }
public print(...);
}
void Main()
{
BigPizza = new Pizza();
BigPizza.Size = 36;
HotBigPizza = new HotPizzaDecorator();
HotBigPizza.Pizza = BigPizza;
HotBigPizza.Hotness = 3;
HotBigCheesyPizza = new CheesyPizzaDecorator();
HotBigCheesyPizza.Pizza = HotBigPizza;
HotBigCheesyPizza.Cheese = "Blue";
HotBigCheesyPizza.print();
HotBigCheesyPizza.size = 28; // ERRRRRR !
}
Now if they all implement the print method and propagate that though the chain, it's all good. But how does that work for the state? I can't access the size property on the HotBigCheesyPizza.
What's the part that I'm missing? Wrong pattern?
Thanks for helping!
Cheers
The decorator pattern is for adding additional behavior to the decorated class without the client needing to adjust. Thus it is not intended for adding a new interface (e.g. hotness, cheese) to the thing being decorated.
A somewhat bad example of what it might be used for is where you want to change how size is calculated: you could create a MetricSizePizzaDecorator that converts the size to/from English/metric units. The client would not know the pizza has been decorated - it just calls getSize() and does whatever it needs to do with the result (for example, to calculate the price).
I would probably not use the decorator in my example, but the point is: it does not alter the interface. In fact, nearly all design patterns come down to that - adding variability to a design without changing interfaces.
one way of adding state is by using a self referential data structure (a list). but this uses the visitor pattern and does more than you probably want. this code is rewritten from A little Java, a few patterns
// a self referential data structure with different types of nodes
abstract class Pie
{
abstract Object accept(PieVisitor ask);
}
class Bottom extends Pie
{
Object accept(PieVisitor ask) { return ask.forBottom(this); }
public String toString() { return "crust"; }
}
class Topping extends Pie
{
Object topping;
Pie rest;
Topping(Object topping,Pie rest) { this.topping=topping; this.rest=rest; }
Object accept(PieVisitor ask) { return ask.forTopping(this); }
public String toString() { return topping+" "+rest.toString(); }
}
//a class to manage the data structure
interface PieManager
{
int addTopping(Object t);
int removeTopping(Object t);
int substituteTopping(Object n,Object o);
int occursTopping(Object o);
}
class APieManager implements PieManager
{
Pie p=new Bottom();
// note: any object that implements a rational version of equal() will work
public int addTopping(Object t)
{
p=new Topping(t,p);
return occursTopping(t);
}
public int removeTopping(Object t)
{
p=(Pie)p.accept(new RemoveVisitor(t));
return occursTopping(t);
}
public int substituteTopping(Object n,Object o)
{
p=(Pie)p.accept(new SubstituteVisitor(n,o));
return occursTopping(n);
}
public int occursTopping(Object o)
{
return ((Integer)p.accept(new OccursVisitor(o))).intValue();
}
public String toString() { return p.toString(); }
}
//these are the visitors
interface PieVisitor
{
Object forBottom(Bottom that);
Object forTopping(Topping that);
}
class OccursVisitor implements PieVisitor
{
Object a;
OccursVisitor(Object a) { this.a=a; }
public Object forBottom(Bottom that) { return new Integer(0); }
public Object forTopping(Topping that)
{
if(that.topping.equals(a))
return new Integer(((Integer)(that.rest.accept(this))).intValue()+1);
else return that.rest.accept(this);
}
}
class SubstituteVisitor implements PieVisitor
{
Object n,o;
SubstituteVisitor(Object n,Object o) { this.n=n; this.o=o; }
public Object forBottom(Bottom that) { return that; }
public Object forTopping(Topping that)
{
if(o.equals(that.topping))
that.topping=n;
that.rest.accept(this);
return that;
}
}
class RemoveVisitor implements PieVisitor
{
Object o;
RemoveVisitor(Object o) { this.o=o; }
public Object forBottom(Bottom that) { return new Bottom(); }
public Object forTopping(Topping that)
{
if(o.equals(that.topping))
return that.rest.accept(this);
else return new Topping(that.topping,(Pie)that.rest.accept(this));
}
}
public class TestVisitor
{
public static void main(String[] args)
{
// make a PieManager
PieManager pieManager=new APieManager();
// add some toppings
pieManager.addTopping(new Float(1.2));
pieManager.addTopping(new String("cheese"));
pieManager.addTopping(new String("onions"));
pieManager.addTopping(new String("cheese"));
pieManager.addTopping(new String("onions"));
pieManager.addTopping(new String("peperoni"));
System.out.println("pieManager="+pieManager);
// substitute anchovies for onions
int n=pieManager.substituteTopping(new String("anchovies"),new String("onions"));
System.out.println(n+" pieManager="+pieManager);
// remove the 1.2's
n=pieManager.removeTopping(new Float(1.2));
System.out.println(n+" pieManager="+pieManager);
// how many anchovies do we have?
System.out.println(pieManager.occursTopping(new String("anchovies"))+" anchovies");
}
}
I believe your component Pizza and your abstract decorator PizzaDecorator are supposed to share the same interface, that way each instance of the decorator is capable of the same operations as the core component Pizza.
I think this falls under the concept of contextual binding, but the Ninject documentation, while very thorough, does not have any examples close enough to my current situation for me to really be certain. I'm still pretty confused.
I basically have classes that represent parameter structures for queries. For instance..
class CurrentUser {
string Email { get; set; }
}
And then an interface that represents its database retrieval (in the data layer)
class CurrentUserQuery : IQueryFor<CurrentUser> {
public CurrentUserQuery(ISession session) {
this.session = session;
}
public Member ExecuteQuery(CurrentUser parameters) {
var member = session.Query<Member>().Where(n => n.Email == CurrentUser.Email);
// validation logic
return member;
}
}
Now then, what I want to do is to establish a simple class that can take a given object and from it get the IQueryFor<T> class, construct it from my Ninject.IKernel (constructor parameter), and perform the ExecuteQuery method on it, passing through the given object.
The only way I have been able to do this was to basically do the following...
Bind<IQueryFor<CurrentUser>>().To<CurrentUserQuery>();
This solves the problem for that one query. But I anticipate there will be a great number of queries... so this method will become not only tedious, but also very prone to redundancy.
I was wondering if there is an inherit way in Ninject to incorporate this kind of behavior.
:-
In the end, my (ideal) way of using this would be ...
class HomeController : Controller {
public HomeController(ITransit transit) {
// injection of the transit service
}
public ActionResult CurrentMember() {
var member = transit.Send(new CurrentUser{ Email = User.Identity.Name });
}
}
Obviously that's not going to work right, since the Send method has no way of knowing the return type.
I've been dissecting Rhino Service Bus extensively and project Alexandria to try and make my light, light, lightweight implementation.
Update
I have been able to get a fairly desired result using .NET 4.0 dynamic objects, such as the following...
dynamic Send<T>(object message);
And then declaring my interface...
public interface IQueryFor<T,K>
{
K Execute(T message);
}
And then its use ...
public class TestCurrentMember
{
public string Email { get; set; }
}
public class TestCurrentMemberQuery : IConsumerFor<TestCurrentMember, Member>
{
private readonly ISession session;
public TestCurrentMemberQuery(ISession session) {
this.session = session;
}
public Member Execute(TestCurrentMember user)
{
// query the session for the current member
var member = session.Query<Member>()
.Where(n => n.Email == user.Email).SingleOrDefault();
return member;
}
}
And then in my Controller...
var member = Transit.Send<TestCurrentMemberQuery>(
new TestCurrentMember {
Email = User.Identity.Name
}
);
effectively using the <T> as my 'Hey, This is what implements the query parameters!'. It does work, but I feel pretty uncomfortable with it. Is this an inappropriate use of the dynamic function of .NET 4.0? Or is this more the reason why it exists in the first place?
Update (2)
For the sake of consistency and keeping this post relative to just the initial question, I'm opening up a different question for the dynamic issue.
Yes, you should be able to handle this with Ninject Conventions. I am just learning the Conventions part of Ninject, and the documentation is sparse; however, the source code for the Conventions extension is quite light and easy to read/navigate, also Remo Gloor is very helpful both here and on the mailing list.
The first thing I would try is a GenericBindingGenerator (changing the filters and scope as needed for your application):
internal class YourModule : NinjectModule
{
public override void Load()
{
Kernel.Scan(a => {
a.From(System.Reflection.Assembly.GetExecutingAssembly());
a.InTransientScope();
a.BindWith(new GenericBindingGenerator(typeof(IQueryFor<>)));
});
}
}
The heart of any BindingGenerator is this interface:
public interface IBindingGenerator
{
void Process(Type type, Func<IContext, object> scopeCallback, IKernel kernel);
}
The Default Binding Generator simply checks if the name of the class matches the name of the interface:
public void Process(Type type, Func<IContext, object> scopeCallback, IKernel kernel)
{
if (!type.IsInterface && !type.IsAbstract)
{
Type service = type.GetInterface("I" + type.Name, false);
if (service != null)
{
kernel.Bind(service).To(type).InScope(scopeCallback);
}
}
}
The GenericBindingGenerator takes a type as a constructor argument, and checks interfaces on classes scanned to see if the Generic definitions of those interfaces match the type passed into the constructor:
public GenericBindingGenerator(Type contractType)
{
if (!contractType.IsGenericType && !contractType.ContainsGenericParameters)
{
throw new ArgumentException("The contract must be an open generic type.", "contractType");
}
this._contractType = contractType;
}
public void Process(Type type, Func<IContext, object> scopeCallback, IKernel kernel)
{
Type service = this.ResolveClosingInterface(type);
if (service != null)
{
kernel.Bind(service).To(type).InScope(scopeCallback);
}
}
public Type ResolveClosingInterface(Type targetType)
{
if (!targetType.IsInterface && !targetType.IsAbstract)
{
do
{
foreach (Type type in targetType.GetInterfaces())
{
if (type.IsGenericType && (type.GetGenericTypeDefinition() == this._contractType))
{
return type;
}
}
targetType = targetType.BaseType;
}
while (targetType != TypeOfObject);
}
return null;
}
So, when the Conventions extension scans the class CurrentUserQuery it will see the interface IQueryFor<CurrentUser>. The generic definition of that interface is IQueryFor<>, so it will match and that type should get registered for that interface.
Lastly, there is a RegexBindingGenerator. It tries to match interfaces of the classes scanned to a Regex given as a constructor argument. If you want to see the details of how that operates, you should be able to peruse the source code for it now.
Also, you should be able to write any implementation of IBindingGenerator that you may need, as the contract is quite simple.