Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
I have a design question for the geeks. I shall present a hypothetical situation.
I have a couple of interfaces required by my application to make an object usable. Let’s say they are;
 
1. IAdult.cs, with two properties
a. Age
b. LicenceNo.
2. IEducated.cs, with two methods
a. Read()
b. Write()
 
If we had to implement an abstract class out of these interfaces, we could simply create a class, say, abstract class EducatedAdult{}. Let’s assume that the implementation of these interfaces shall remain the same most of the times.
 
Now we define three different objects with their own respective inheritances and a set of respective properties;
 
1. Carpenter.cs (derives from class A)
2. Plumber.cs (derives from class B)
3. Programmer.cs (derives from class C)
 
(Here class A, B, C belong to an external library) Now to make these objects usable in the Program, they need to implement the above given interfaces. So the issue is that for each one of these classes, I’ll have to explicitly implement the above stated interfaces. Could there be a better design where I do not have to implement the interfaces redundantly in all the classes. This could be a solution, had it been possible;
class EducatedAdult<t>: t, IAdult, IEducated 
{ 
 <implementation of="" interfaces=""> 
}
</implementation></t>
And later, maybe, I could just initialize my derived classes like;
 
Carpenter carpenter = new EducatedAdult<carpenter>().</carpenter>
 
Not that this would be an ideal solution, ‘cause the public interface of the carpenter object shall still not include my interface members (without required casting). But then, what could be the most suitable design?
Posted 30-Apr-11 0:10am
Edited 30-Apr-11 0:58am
v2
Comments
Albin Abel at 30-Apr-11 6:18am
   
Hi VermaManish, Is the stackoverflow.com response solved your issue or still waiting for a better response? :)
Nishant Sivakumar at 30-Apr-11 12:37pm
   
Dude, you are everywhere huh? SO, CP, and MSDN? :-)
VermaManish at 30-Apr-11 12:51pm
   
Who me? No! Its Lord Krishna who's everywhere - The Omnipresent! :)
Nishant Sivakumar at 30-Apr-11 12:54pm
   
No, not you. I meant Albin. And Krishna is not omnipresent, if so he'd have been there for the WC finals and he clearly wasn't! *grin*
Albin Abel at 30-Apr-11 14:48pm
   
Hi Nishant, It is nice to meet you everywhere too. :) :)
VermaManish at 30-Apr-11 6:23am
   
Hi Albin,
Nice to see you here. But I am still looking for a better design.
Thanks
Manish
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 3

Your problem is classified in two parts:
1) Adequate modeling,
2) Technical aspects of week form of multiple inheritance.
 
1) Adequate modeling
 
I think you missing one important principle: if you have 1-3 design options using different technical tools. You cannot just ask "what could be the most suitable design?". It depends on semantic of the members of you terminal classes; if you know the classes and the members, you should fist ask "do I really need them?".
 
Let me illustrate this. What is IAdult? I don't need it! You need IPerson or just a class Person. A person always has the age and can have null or non-null License. It would cover all people including children. When a child obtains License, the class instance changes. For this purpose, your need LicenseNumber? (nullable type). You don't need age, ever. You need date of birth instead. Having age will cause you to change the instance all the time.
 
You don't need IEdicated as well. Consider everyone as educated, this is fair. You should create a type Education. All persons will instantiate the instance of this type, but the qualify of education will be changed; so the values in this instance will change (grow, hopefully).
 
What complexity has left? None! You see, by simple analysis I removed all your needs in multiple inheritance by turning it all into on single base class. I made the picture simpler technically yet more adequate to the real life we're trying to model.
 
2) Technical aspect of week form of multiple inheritance.
 
After the model is simplified, let's go back to multiple inheritance from more then one interface, so called week form of multiple inheritance. How to make different implementation in different classes in a way free from a predefined hierarchy of implementation classes? I don't want to use your interfaces anymore. Let's talk about interfaces IFirst and ISecond.
 
I would suggest using a technique of implementation helpers. Something like this:
 
public interface IFirst {
    void A();
    void B();
}
public interface ISecond {
    void A();
    void C();
}
 
public class FirstHelperDetail { }
public class FirstHelper : IFirst {
    public FirstHelper(FirstHelperDetail userDetail) {
        this.UserDetail = userDetail;
    }
    void IFirst.A() { /* implementaion using UserDetail */ }
    void IFirst.B() { /*...*/ }
    FirstHelperDetail UserDetail;
}
 
public class SecondHelper : ISecond {
    public SecondHelper(System.Func<string, bool> userPredicate) {
        this.UserPredicate = userPredicate;
    }
    void ISecond.A() { /* implementaion using UserDetail */ }
    void ISecond.C() {
        if (UserPredicate != null) { /*...*/ }
        //...
    }
    System.Func<string, bool> UserPredicate;
}
 
class User : IFirst, ISecond {
    internal User(/*...*/) {
        FirstHelper = new FirstHelper(new FirstHelperDetail(/*...*/));
        SecondHelper = new SecondHelper(predicate);
    }
    void IFirst.A() { FirstHelper.A(); }
    void IFirst.B() { FirstHelper.B(); }
    void ISecond.A() { SecondHelper.A(); }
    void ISecond.C() { SecondHelper.C(); }
    IFirst FirstHelper;
    ISecond SecondHelper;
    System.Func<string, bool> predicate = (name) => { /* use name... */; return false; };
}
 
The sample demonstrate separate techniques of parametrization of helpers. Also, pay attention to explicit form of interface method implementation; this style is usually better then public: the method can not be called through the reference as class, only as interface which provide nice isolation. In particular, one can have too methods A of the same signatures. This style of interfacing is of course optional.
 

—SA
  Permalink  
v3
Comments
VermaManish at 1-May-11 5:19am
   
This is perfectly valid in some cases. We could even use extension methods that can achieve the same pattern a little more elegantly. But let's agree to your argument that we should have bigger preference for language independent semantics. And so, your approach of using implementation helpers seems quite valid. But Nishant’s solution has one big advantage - we are able to encapsulate the implementation of our interfaces. This advantage of (encapsulated implementation) holds big relevance in case of my solution, even if it is at the cost of using language specific semantics. And after all, if everybody would avoid using language specific semantics, there wouldn’t be a need for second language. But I do really appreciate a good pattern that your solution manifests. Thanks
SAKryukov at 1-May-11 14:45pm
   
Agree.
Would you formally accept this answer?
I think it is adequate based on your formulation of the problem.
--SA
VermaManish at 2-May-11 3:17am
   
With pleasure! But it was Nishant's solution (Solution 3) that worked for me.
SAKryukov at 2-May-11 4:17am
   
Thank you, Verma. It's good Nishant's code was better for your, but I hope you understand I provided some wider understanding of the problem. Isn't it the meaningful criterion for acceptance of the solution, along with ad-hoc purpose? :-)
--SA
Albin Abel at 2-May-11 0:07am
   
My 5 for language independent semanatics. This way provide little flexibility to the user class how to use the interface implementation, whereas encapsulating the interface methods hinders further flexibility. void IFirst.A() { FirstHelper.A(); } and I have flexibility to use void IFirst.A() { NewHelper.A(); }. By design I like this way. Nishant's answer satisfy Verma's question. So question answered and you solution is a better design. :) 5++
SAKryukov at 2-May-11 1:18am
   
Thank you, Albin. I only did not understand what language-independent did you find in my solution. Everything using just the framework is really language-independent; and my syntax is C#-only...
--SA
Albin Abel at 2-May-11 9:12am
   
Your syntax is c#, but this model is applicable to other object oriented languages as well, except the predicate things. :)
SAKryukov at 2-May-11 13:45pm
   
What a minute. Predicate is just a variable name, common for all languages, in my code it only requires generics which is common to all languages, but anonymous is not...
--SA
Albin Abel at 2-May-11 14:47pm
   
Right, you were talking about syntax, these lamda syntax is not common to all languages
SAKryukov at 2-May-11 1:21am
   
As to better design or not... I tried to demonstrate that the design really depends on the real-life problem and its modeling. Good technical approach to one case maybe pretty bad for another...
Thank you.
--SA
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

Here's a simplified example of one possible approach :
 
class Program
{
    static void Main()
    {
        EducatedAdult<Carpenter> eac = new EducatedAdult<Carpenter>();
        eac.Age = 10;
        eac.Read();
        Carpenter cpr = eac;
        cpr.DoWork();
    }
}
 
interface IAdult
{
    int Age { get; set; }
}
 
interface IEducated
{
    void Read();
}
 
class EducatedAdult : IAdult, IEducated
{
    public void Read()
    {
    }
 
    public int Age
    {
        get
        {
            return 18;
        }
 
        set
        {
        }
    }
}
 
class A { }
 
class Carpenter : A
{
    public void DoWork()
    {
    }
}
 
class B { }
 
class Plumber : B { }
 
class EducatedAdult<T> : EducatedAdult where T:new()
{
    private T t;
 
    public EducatedAdult()
    {
        this.t = new T();
    }
 
    public static implicit operator T(EducatedAdult<T> eat)
    {
        return eat.t;
    }
}
  Permalink  
v2
Comments
VermaManish at 30-Apr-11 13:31pm
   
I think your solution is par excellent!
I'll have to do few more tests related to serializing the generic EducatedAdult, before I come back.
Thanks!
Albin Abel at 30-Apr-11 14:49pm
   
Sure, my 5++
SAKryukov at 30-Apr-11 23:14pm
   
Things can be simplified through better analysis but needs some more flexibility; also, the final solution depends on semantic.
 
Please see my variant.
--SA
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

How about some sort of construct like:
 
class MyCarpenter : carpenter
{
    public EducatedAdult EA = null;
 
    public MyCarpenter()
    {
        EA = new EducatedAdultSubClass();
    }
}
 

i.e. embed rather than inherit - you can put whatever behaviours you like in your EducatedAdult class and any sub-classes (do you even need the base EducatedAdult class to be abstract?) and implement them once only.
 
I'm sure others will come up with alternative ways of doing it, but this seems to me to be relatively straightforward.
  Permalink  
Comments
VermaManish at 30-Apr-11 6:22am
   
The application that shall use these objects identifies the interfaces (IAdult, IEducated) only. So I need to implement these contracts to make these objects (Carpenter, Programmer, Plumber) usable.
SAKryukov at 30-Apr-11 23:12pm
   
The idea make sense and should be use an many cases but have limitations. Could be a variety of methods. My 4. Thinks are more simple and more complext at the same time.
 
Please see my solution.
--SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 OriginalGriff 245
1 Jochen Arndt 155
2 PIEBALDconsult 150
3 Afzaal Ahmad Zeeshan 120
4 DamithSL 115
0 OriginalGriff 5,695
1 DamithSL 4,591
2 Maciej Los 4,012
3 Kornfeld Eliyahu Peter 3,480
4 Sergey Alexandrovich Kryukov 3,190


Advertise | Privacy | Mobile
Web01 | 2.8.141220.1 | Last Updated 30 Apr 2011
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100