4

Let's say I have two base abstract classes with completely different functionality: Laptop and Smartphone. (Suppose the functionality is completely different). And in my current project I had already many implementations of laptops and smartphones, and they always were completely different.

But suddenly I received a request to add a class that is an implementation of pc-tablet, that is actually have functions of both smartphone and laptop. It is too late to change the base classes, and actually I'm very sure that this pc-tablet will appear only once.

The problem is, I should be able to contain my pc-tablet in the conainer for smartphones, but it should also be laptop, because of the inherited functionality (actually beside that, in some part of the project pc-tablet is used only as laptop, and it doesn't need smartphone functionality. Moreover it is bad to look at pc-tablet as smartphone for that particular part of the project). So I have PcTabletAsLaptop : Laptop class, that is actually a laptop, and not a smartphone.

My solution is to add a wrapper:

class PcTablet : SmartPhone
{
    private PcTabletAsLaptop _pcTablet;

    // Here goes all the methods of PcTabletAsLaptop as proxies:

    public void Call(int number)
    {
      _pcTablet.Call(number);
     }

     // .....
}

There are 200+ methods and I want them to be generated automatically from PcTabletAsLaptop.

This solution looks quite complicated. My question is it good, or maybe there are some simplier ways to do that?

4
  • Can you not add a further base class "MobileDevice" and have them all inherit from that? Commented Jun 29, 2012 at 10:35
  • 200+ methods? Perhaps it's time to consider some redesigning. Commented Jun 29, 2012 at 10:49
  • @DaveBish I do not want to change original hierarchy, as the project is already in production. Actually, this is a requirement from customer (we are writing framework, so code design is considered as part of the requirement too) Commented Jun 29, 2012 at 12:15
  • @ChrisSinclair many of the mobile devices are wrappers around C++ dlls, with minimum logic, including this one. In most cases these wrappers are generated by some 3rd parties, and we don't have any control about that, however we have the wrapper sources and we can change them. Still it's bad to make full redisigning, as because of any change in C++ dll, it should be possible to take the wrapper from 3rd party with minimum changes Commented Jun 29, 2012 at 12:17

3 Answers 3

3

You could extract an interface form both SmartPhone & Laptop then create a third interface PcTablet that will inherit from the first two. That way, you will be able to use the PcTablet as an Smartphone or a Laptop.

Edit:

To be able to reuse the logic inside each SmartPhone & Laptop you could use the Adapter Pattern so PcTablet should look like something like that :

public class PcTablet :ISmartPhone, ILaptop
{
     private SmartPhone _smartphone;
     private Laptop _laptop;
     public void ISmartPhone.Call()
     {
         _smartPhone.Call();
         // OR IMPLEMENT THE RIGHT BEHAVIOR 
         //INSTEAD OF CALLING _smartPhone.Call()
     }
}

Of course you will have to create a smartphone and the laptopn in the constructor but it should do the trick ! That ways, you'll be able to reuse code in Laptop & SmartPhone but also override their behavior in the case that they don't provide the right one.

Sign up to request clarification or add additional context in comments.

3 Comments

Nice idea, but what about the logic from base classes of SmartPhone and Laptop? I'd like it to be reused with minimum effort.
Yep, it's good enough and it was my first intention to do. The only that scares me here is that I have to implement these wrappers for each method of _smartphone and _laptop (they are many)
@Archeg Yes I understand but to be able to use your PCTablet as a Laptop & SmartPhone at the same time and to be able to reuse code from both classes... I don't see many other ways cleaner then this. Also It's felxible enough that if it -let said Call function- doesn't work the way you want, you're free to change the implementation without affecting the base class. At the opposite, all the changes you do in the bases classes will affect the PCTablet class.. which it good and bad at the same time but, again, you can override the behavior!
1

If you need multiple inheritance - in most cases you are doing something wrong or trying to solve a problem in a wrong way. What about hierarchy like shown below?

internal class PcTabletAslaptop : LaptopBase
{
    // here is you can expose / override laptop specific stuff
}

internal class PcTabletAsSmartphone : SmartphoneBase
{
    // here is you can expose / override smartphone specific stuff
}

public interface IPcTablet
{
   // just expose PcTablet specific API
}

public sealed class PcTablet : IPcTablet
{
   private PcTabletAsSmartphone asSmartphone;
   private PcTabletAsLaptop asLaptop;
}

3 Comments

Your solution looks like mine, as only that I've made PcTablet derived from SmartPhone. I guess your solution may even be better. But still I need to make proxies to those 200+ methods, for PcTablet to call one of the fields. So, my question is it the way it should be?
So public API fo both laptop&&smartphone classes is not enough for the PcTablet class and you need to access protected/private interface? If so could you please bring one of the examples when you need accessing private/protected interface of laptop/smartphone?
I meant that PcTabletAsSmartphone has Call() method, and in that case PcTablet also should have Call() method, that calls asSmartphone.Call(). And I have like 200+ such methods. As I'm hiding PcTabletAsSmartphone, I need to write this method as proxy to the hidden inner instance. Of course I can expose asSmartphone instance, but that will break all the design
0

I think you can think in terms of composition rather than aggregation.

aggregation-vs-composition

What about SmartPhone contains Tablet.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.