2

Let's assume we have something like that:

class Page{
    Header header;
    Body body;
    Footer<TFooterModel> footer;  //TFooterModel is a type of content (subcontrol in some sense) that loaded inside footer.

    public Page(Header h, Body b, Footer<TFooterModel> f){...} //Let's assume that we setting part in constructor or using Builder pattern. 

}

So, Footer is generic one. However, it will be logically wrong, to make Page also generic and use Page<TFooterModel>, just because I don't really use TFooterModel anywhere inside, except specifying Footer's type. Converting Footer to inheritance chain also seem wrong, since it's just a container for some content and there is no sense in inheritance, since children will be identical. This is looks like design issue for me, but I'm not sure how to fix it.

So, what is a proper way to handler those scenario, which really great developers use?


Footer it's just a container, which load some content using loadContent(BaseContent content), but it has an event. onContentLoaded(OnContentLoadedHandler<ContentImpl> handler), so just single difference between children will be a type of OnContentLoadedHandler used, that's why I think that inheritance is something to much.


There was some options proposed.

  1. Create non-generic Footer, inherit generic footer from non-generic, and use non-generic inside Page
  2. Pass OnContentLoadedHandler in Footer's constructor and avoid generic (however my personal opinion, it's could have some pitfalls, due to type resolving when calling handler (if it's lambda for example, or if it's dynamic, but i'm not fully sure.))
  3. Add interface and use it instead (probably logically similar to 1.)
  • I'm not sure I understand why there's a problem with just using Footer<TFooterModel> as you show above...? What exactly is the problem that you need to "fix"? – Jules Aug 8 '16 at 23:54
  • What language is this? – Winston Ewert Aug 9 '16 at 1:13
  • 1
    The part of the question which is extremely unclear is: where/when shall the concrete type for the type variable TFooterModel be provided (I am pretty sure you meant it to be a type variable, otherwise there would not be any problem.) – Doc Brown Aug 9 '16 at 8:40
  • Let's assume they added in constructor – Ph0en1x Aug 10 '16 at 12:51
  • Broken english. – Tulains Córdova Aug 10 '16 at 12:58
2
class Page {
    Header header;
    Body body;
    Footer<TFooterModel> footer;
}

If TFooterModel is a concrete type (class or interface in your codebase, and all of its parameters instantiated to concrete types) this is fine; there is no need to define a separate class that inherits from it.

If TFooterModel is instead a type variable (not a concrete type), then this code is ill-typed; Page would need to have that type variable as its parameter as well (Page<TFooterModel>). There's no getting around this, because all actual instantiated objects of a generic type must be instantiated with some choice of concrete type for all of their type parameters.

So something has to instantiate Footer's type parameter to a concrete type. If Page is not going "pass up" a type parameter for this, then it might as well be Page itself that instantiates Footer's parameter. That way:

  • If TFooterModel is a concrete type, then the code example is already the best solution.
  • If TFooterModel is a type variable, then all that Page needs to do is change it to a concrete type.

The other idea that has been presented is that, instead of Page instantiating Footer's parameter to a concrete type, have some third class that extends from Footer just to do this instantiation. This is just pointless, and defeats the purpose of using generics in the first place—that we can reuse Footer with various instantiations of its parameters without having to write new classes or perform unsafe runtime casts. The only reason to subclass from Footer would be to provide some additional functionality that's not already generically present in the superclass.

  • OP specifically requested a solution that doesn't require a generic argument on Page. Good point about TFooterModel possibly being a concrete type, but in this case, I believe the OP was describing a situation where TFooterModel is a generic type parameter (and used C# naming conventions for type parameters). If the OP hadn't specifically requested a non-generic Page solution, I would've agreed with this answer. – wablab Aug 9 '16 at 0:30
  • @wablab: I've edited my answer to make it clearer, but I fully stand by it otherwise. Keep in mind that OP didn't even specify whether TFooterModel is a concrete type or a type variable—we can't even tell whether the example code is well-typed or not! – sacundim Aug 9 '16 at 2:00
  • TFooterModel is a type of content (subcontrol in some sense) that loaded inside footer. – Ph0en1x Aug 10 '16 at 12:53
1

Create a class named Footer (not generic). Change your Page.footer to this type:

class Page {
  Header header;
  Body body;
  Footer footer; // note we changed the type of this field
}

Derive another class named Footer<TFooterModel> from your base Footer class:

public class Footer<TFooterModel> : Footer {
  ...
}

Instantiate your footer however you normally do, and assign it to Page.footer.


To clear up some confusion about this answer:

  1. Why not make Page generic (i.e. Page<TFooterModel>)? In short: because the OP asked for a solution that didn't require a generic argument on the Page class.
  2. Why is this answer better than option 3 in the OP's list? It's not necessarily better. It's just my preference to use a class here since body and header are classes and are basically the same thing as footer (containers for page data).
  3. Why is this answer better than option 2 in the OP's list? It's not necessarily better. Option 2 would probably work but seemed less straightforward than this option (after all, something has to host those generic callbacks you'd be passing in, so you're probably still going to end up with a Something<TFooterModel>.
  • Why I think that make Page generic - is a bad idea. In M.Fowler's book or in Code Complete (don't remember for sure) was mention, that even if you pass variable in class or method, and don't use it somewhere in class/method, instead of just passing down to other class/method - this is a "smell" which indicate some design problem. For my point of view, things goes even worse if we talk about generic type. This will be absolutely confusing for class client - why he need to make this class typed, and especially which type he need to use, since this type don't really use anywhere in class code. – Ph0en1x Aug 10 '16 at 13:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.