Generating pass-through code when "preferring composition over inheritance"
Asked Answered
S

4

20

Problem

Let's say I'm trying to model a cell phone as a combination of a regular phone and a PDA. It's sort of a multiple inheritance scenario (a cell phone is a phone, and it is a PDA). Since C# doesn't support multiple inheritance, this pretty much calls for some kind composition. Plus, let's say that I have other reasons to favor composition anyway.

The thing I always wonder: Are there any tools that will generate all the inevitable pass-through code automatically?

Let me flesh out my example with some actual code:

Interfaces:

public interface IPhone
{
    public void MakeCall(int phoneNumber);
    public void AnswerCall();
    public void HangUp();
}

public interface IPda
{
    public void SendEmail(string[] recipientList, string subject, string message);
    public int LookUpContactPhoneNumber(string contactName);
    public void SyncWithComputer();
}

Implementations:

public class Phone : IPhone
{
    public void MakeCall(int phoneNumber) { // implementation }
    public void AnswerCall() { // implementation }
    public void HangUp() { // implementation }
}

public class Pda : IPda
{
    public void SendEmail(string[] recipientList, string subject, string message) { // implementation }
    public int LookUpContactPhoneNumber(string contactName) { // implementation }
    public void SyncWithComputer() { // implementation }
}

The CellPhone class

public class CellPhone : IPhone, IPda
{
    private IPhone _phone;
    private IPda _pda;

    public CellPhone(IPhone phone, IPda pda)
    {
        _phone = phone;
        _pda = pda;
    }

    public void MakeCall(int phoneNumber)
    {
        _phone.MakeCall(phoneNumber);
    }

    public void AnswerCall()
    {
        _phone.AnswerCall();
    }

    public void HangUp()
    {
        _phone.HangUp();
    }

    public void SendEmail(string[] recipientList, string subject, string message)
    {
        _pda.SendEmail(recipientList, subject, message);
    }

    public int LookUpContactPhoneNumber(string contactName)
    {
        return _pda.LookUpContactPhoneNumber(contactName);
    }

    public void SyncWithComputer()
    {
        _pda.SyncWithComputer();
    }
}

Writing the CellPhone class is tedious and error-prone:

All this class really does is act as a conduit for the Phone and Pda classes. There is really no reason human effort should be required to type out all these pass-through statements (like _phone.MakeCall(phoneNumber);). It's just exposing the public interface of a couple member fields.

Questions

  1. Is there a tool (preferably free :)) that will save me from the error-prone tedium of writing pass-through methods? I'm aware that I can automatically generate the stubs using VS, but this only gets me half the way there.

  2. Can you rate the feasibility and desirability of such a feature? Would it be worth putting in a suggestion to Microsoft to add this type of code generation? Would you upvote it if I did? If not, what objections do you have?

Edit

Everyone seems to be saying the same thing: Why don't I just make _phone and _pda into public properties? My objection to this is that it violates the "principle of least knowledge". The client of my CellPhone class should just do the things a cell phone does, it shouldn't have to deal with figuring out which features are Phone features and which are Pda features. This creates additional dependencies and makes the features of the CellPhone interface less obvious.

Also, don't focus just on this example. What if I were writing an adapter? It might contain several interface members that are just pass-throughs, but it might also contain some unique members with unique implementation. I believe there are many cases where pass-through code is a good thing, I just don't like writing it.

Supporter answered 27/1, 2010 at 21:33 Comment(3)
Just don't see why you'd want to expose those same methods again. Why note just add methods, "getPhone" or "getPDA" and then be on your way. Unless you're going to actually have some intelligence in the CellPhone class, in which case this boilerplate code is irrelevant.Refine
@yar, well that would now mean the client class has to get involved with the plumbing of the CellPhone class. The Client shouldn't have to know that the CellPhone is really a combination of a Phone and and Pda. It should deal directly with the CellPhone itself. It's basically the "Principle of least knowledge - only talk to your immediate friends."Supporter
yeah, I see that. I guess there's no reason for a client to know whether something is on the Phone or PDA.Refine
B
17

Yes, you can generate the methods using the brilliant VS add-in, ReSharper

Choose the "generate delegating methods" option from the code-generation menu (Alt-Insert with the default shortcut scheme).

Where you have a class that implements an interface, containing a field that implements the same interface, R# will give you an option to generate the pass-through code. It can work with any number of interfaces, too.

Beata answered 27/1, 2010 at 22:35 Comment(1)
Thanks for your answer, Mark, +1. And I guess this proves that it really is feasible :)Supporter
T
2

I have seen this suggestion before (not necessarily on Stack Overflow). It was a while ago. I believe the author created a Connect issue, though I don't know its status.

The proposed syntax was one of the following:

public class CellPhone : IPhone, IPda
{
    private readonly IPhone _phone implements IPhone;
    private readonly IPda _pda : IPda;

    // ...
}
Tirzah answered 27/1, 2010 at 22:18 Comment(3)
Interesting, so an actual language feature. I thought about proposing something like this in my question, but I thought better of it. If you change the definition of IPhone, you could unknowingly break classes that depend on CellPhone because the pass-through methods are not explicitly present. I admit such a solution is tempting though because it avoids polluting the class with so much boilerplate stuff.Supporter
Changing an interface causes that problem everywhere :-) I'm sure there would also be nightmarish method resolution issues. It does looks nice, though.Tirzah
With the advent of Roslyn, maybe someone will implement this one day.Oakland
C
1

Adding some visuals and detail to a previously supplied answer.

  1. add the interface to the class you wish to be the wrapping class

    class MyWebElement : IWebElement { }
    

  1. Find/Click "Delegate implementation of "YourInterfaceHere" to a new field Delegate Implementation

  1. Select your options Delegate options

  1. Click finish and enjoy your new class

    class MyWebElement : IWebElement
    {
        private IWebElement _webElementImplementation;
        public IWebElement FindElement(By @by)
        {
            return _webElementImplementation.FindElement(@by);
        }
    
        public ReadOnlyCollection<IWebElement> FindElements(By @by)
        {
            return _webElementImplementation.FindElements(@by);
        }
    
        public void Clear()
        {
            _webElementImplementation.Clear();
        }
    
        public void SendKeys(string text)
        {
            _webElementImplementation.SendKeys(text);
        }
    
        public void Submit()
        {
            _webElementImplementation.Submit();
        }
    
        public void Click()
        {
            _webElementImplementation.Click();
        }
    
        public string GetAttribute(string attributeName)
        {
            return _webElementImplementation.GetAttribute(attributeName);
        }
    
        public string GetCssValue(string propertyName)
        {
            return _webElementImplementation.GetCssValue(propertyName);
        }
    
        public string TagName
        {
            get { return _webElementImplementation.TagName; }
        }
    
        public string Text
        {
            get { return _webElementImplementation.Text; }
        }
    
        public bool Enabled
        {
            get { return _webElementImplementation.Enabled; }
        }
    
        public bool Selected
        {
            get { return _webElementImplementation.Selected; }
        }
    
        public Point Location
        {
            get { return _webElementImplementation.Location; }
        }
    
        public Size Size
        {
            get { return _webElementImplementation.Size; }
        }
    
        public bool Displayed
        {
            get { return _webElementImplementation.Displayed; }
        }
    }
    
Crossarm answered 11/1, 2017 at 15:15 Comment(1)
This needs ReSharper though.Publea
G
-1

Interesting question. Can the CellPhone class really rely on the implementation of IPhone methods provided by an existing, concrete IPhone class? Or is it more likely that CellPhone will need some custom code backing those methods?

Looking at your code (though I don't know much about your requirements) makes me want to write something like this:

public class CellPhone 
{
    private Phone _phone;
    private Pda _pda;

    public CellPhone(Phone phone, Pda pda)
    {
        _phone = phone;
        _pda = pda;
    }

    public IPhone getPhone()
    {
        return _phone;
    }

    public IPda getPda()
    {
        return _pda;
    }

    public void MakeCall(string contactName) {
        int phoneNumber = _pda.LookUpContactPhoneNumber(contactName);
        _phone.MakeCall(phoneNumber);
    }

}

Question 2:

I don't really like auto-generated code. Even if the machine generates it -- and without errors -- you'll still be responsible for maintaining it. Those methods seem like so much noise.

Gules answered 27/1, 2010 at 21:50 Comment(5)
1. Using getPhone() forces the client to care that CellPhone is implemented in terms of Phone and PDA. 2. It's extra typing/syntactic noise any time you want to use a Phone or PDA method. 3. A CellPhone is a Phone and should be substitutable for one. A modern CellPhone is also a PDA and should be substitutable for one.Retrogress
I have no disagreement with these points; the OP asked how to avoid coding the "pass through" code for IPhone & IPda methods, and this is one method of doing so. It may not be a good choice in every situation or even in this one. I could add that it's likely the heavy-lifting for methods MakeCall() and SendEmail() would be better placed in service objects tied to things like protocols, not directly inside IPhone impls; this approach means that composing an IPhone impl would buy you little, and perhaps you shouldn't bother. In any case CellPhone should provide MakeCall(string contactName).Gules
specifically, I want to avoid hand-coding the pass-through code, not eliminate the pass-through code. I agree with you that the code is noisy, but forcing clients to deal with Pda and Phone objects is also noisy, and it means they are dependent on three classes (CellPhone, Pda, and Phone) instead of one. If I now move the MakeCall() implementation out of Phone and into Service object, this would be a breaking change. All objects that rely on CellPhone.Phone.MakeCall() would have to change to CellPhone.Service.MakeCall(), something I definitely want to avoid.Supporter
@DanM no, not move the MakeCall() method itself, just the heavy lifting. Imagine you're implementing a phone that makes calls over "public switched telephone network" (PSTN); you might have a PtsnServiceBroker class that knows how to openPhoneLine(), sendDidget(), and disconnect(). The implementation of your MakeCall() method would be a bunch of calls to these service methods. Then you might have a different IPhone impl that doesn't know anything about PSTN and instead makes calls over VoIP.Gules
I was just using your example to make my point, but I guess I incorrectly interpreted your example :)Supporter

© 2022 - 2024 — McMap. All rights reserved.