How to design around the lack of multiple inheritance?

Using interfaces will not work because I want one implementation. Using this solution will end with a lot of redundant code, because I plan to have quite a few subclasses (composition versus inheritance). I decided that a solution for specific tasks is what I am looking for, and I cannot come up with anything elegant.

Basically, I want classes to have separate properties, and for those properties that should be bound at design time to any subclass that I choose. Say I have a ninja class. I would like to be able to do arbitrary subclasses such as "gray ninja", where a gray ninja will always have a sword and throw stars. Then maybe redNinja, who will always have a sword and cloak. Obviously, swords, stars and capes will have their own implementation - and here I can not use interfaces. The closest solution I could find was a decorator template, but I do not want to use this functionality at runtime. Is branching the best solution? Where inside the Black Ninja class constructor do I pass it through the sword constructors and throwing the Star? (those that are abstract classes)

not encoded at the time, and the reading didn't go too far - forgive me if the answer is simple.

Edit: Answered my own question. I cannot mark this as an “answer” until tomorrow. Please let me know if there is a problem with this that I did not catch. All reading this issue made me make it awesome. Learned quite a bit.

+3
source share
4 answers

, mix-ins . , - vb.net(, , , ). , . , , .

, - , , . . , , . , .

, vb.net, .

Imports System.Runtime.CompilerServices 'for extension methods

Public Interface ISword
End Interface
Public Interface IThrowingStar
End Interface

Module ExtensionMethods

    <Extension()>
    Public Sub swingSword(ByVal hasASword As ISword)
        Console.WriteLine("Sword has been swung")
    End Sub

    <Extension()>
    Public Sub throwStar(ByVal hasAStar As IThrowingStar)
        Console.WriteLine("Star has been thrown")
    End Sub

End Module

Public Class RedNinja
    Inherits Ninja
    Implements IThrowingStar, ISword

    Public Sub New()
    End Sub

End Class

Public MustInherit Class Ninja

    private curHealth as Integer

    Public Sub New()
        curHealth = 100
    End Sub

    Public Function getHP() As Integer
        Return curHealth
    End Function

End Class

Module Module1

    Sub main()

        Console.WriteLine("Type any character to continue.")
        Console.ReadKey()

        Dim a As New RedNinja
        a.swingSword() 'prints "Sword has been swung"
        a.throwStar()  'prints "Star has been thrown"

        Console.WriteLine("End of program - Type any key to exit")
        Console.ReadKey()

    End Sub
End Module
0

. "++", - .

// base class for all ninjas
public class Ninja {

  // default constructor
  public Ninja() { ... }

  // default destructor
  public ~Ninja() { ... }
} // class

public class StarNinja: public Ninja {

  // default constructor
  public StarNinja() { ... }

  // default destructor
  public ~StarNinja() { ... }

  public void throwStars() { ... }
} // class

public class KatannaNinja: public Ninja {

  // default constructor
  public KatannaNinja() { ... }

  // default destructor
  public ~KatannaNinja() { ... }

  public void useKatanna() { ... }
} // class

public class InvisibleNinja: public Ninja {

  // default constructor
  public InvisibleNinja() { ... }

  // default destructor
  public ~InvisibleNinja() { ... }

  public void becomeVisible() { ... }  
  public void becomeInvisible() { ... }
} // class

public class FlyNinja: public Ninja {

  // default constructor
  public FlyNinja() { ... }

  // default destructor
  public ~FlyNinja() { ... }

  public void fly() { ... }  
  public void land() { ... }
} // class

public class InvincibleNinja: public Ninja {

  // default constructor
  public InvincibleNinja() { ... }

  // default destructor
  public ~InvincibleNinja() { ... }

  public void turnToStone() { ... }  
  public void turnToHuman() { ... }
} // class

// --> this doesn't need to have the same superclass,
// --> but, it helps
public class SuperNinja: public Ninja {

  StarNinja* LeftArm;
  InvincibleNinja* RightArm;
  FlyNinja* LeftLeg;
  KatannaNinja* RightLeg;
  InvisibleNinja* Body;

  // default constructor
  public SuperNinja() { 
    // -> there is no rule to call composed classes,
    LeftArm = new StarNinja();
    RightArm = new InvincibleNinja();
    LeftLeg = new FlyNinja();
    RightLeg = new KatannaNinja();
    Body = new InvisibleNinja();
  }

  // default destructor
  public ~SuperNinja() { 
    // -> there is no rule to call composed classes
    delete LeftArm();
    delete RightArm();
    delete LeftLeg();
    delete RightLeg();
    delete Body();
  }

  // --> add all public methods from peers,
  // --> to main class
  public void throwStars() { LeftArm->throwStars(); }
  public void useKatanna() { RightLeg->useKatanna(); }  
  public void becomeVisible() { Body->becomeVisible() }  
  public void becomeInvisible() { Body->becomeInvisible() }
  public void fly() { LeftLeg->fly() }  
  public void land() { LeftLeg->land() }
  public void turnToStone() { RightArm->turnToStone(); }  
  public void turnToHuman() { RightArm->turnToHuman(); }
} // class

, . , , , , , .

, , , , , .

public interface INinja {
  public void NinjaScream() { ... }
} // class

public interface IStarNinja {
  void throwStars();
} // class

public interface IKatannaNinja {
  void useKatanna();
} // class

public interface IInvisibleNinja {
  void becomeVisible();
  void becomeInvisible();
} // class

public interface CFlyNinja {
  void fly();
  void land();
} // class

public interface IInvincibleNinja {
  void turnToStone() { ... }  
  void turnToHuman() { ... }
} // class

// base class for all ninjas
public class CNinja: public INinja {

  // default constructor
  public CNinja() { ... }

  // default destructor
  public ~CNinja() { ... }

  public void NinjaScream() { ... }
} // class

public class CStarNinja: public CNinja, INinja {

  // default constructor
  public CStarNinja() { ... }

  // default destructor
  public ~CStarNinja() { ... }

  public void NinjaScream() { ... }
  public void throwStars() { ... }
} // class

public class CKatannaNinja: public CNinja, IKatannaNinja {

  // default constructor
  public CKatannaNinja() { ... }

  // default destructor
  public ~CKatannaNinja() { ... }

  public void NinjaScream() { ... }
  public void useKatanna() { ... }
} // class

public class CInvisibleNinja: public CNinja, IInvisibleNinja {

  // default constructor
  public CInvisibleNinja() { ... }

  // default destructor
  public ~CInvisibleNinja() { ... }

  public void becomeVisible() { ... }  
  public void becomeInvisible() { ... }
} // class

public class CFlyNinja: public CNinja, IFlyNinja {

  // default constructor
  public CFlyNinja() { ... }

  // default destructor
  public ~CFlyNinja() { ... }

  public void fly() { ... }  
  public void land() { ... }
} // class

public class CInvincibleNinja: public CNinja, IInvincibleNinja {

  // default constructor
  public CInvincibleNinja() { ... }

  // default destructor
  public ~CInvincibleNinja() { ... }

  public void turnToStone() { ... }  
  public void turnToHuman() { ... }
} // class

// --> this doesn't need to have the same superclass,
// --> but, it helps
public class CSuperNinja: public CNinja,
  IKatannaNinja,
  IInvisibleNinja,
  IFlyNinja,
  IInvincibleNinja  
{

  CStarNinja* LeftArm;
  CInvincibleNinja* RightArm;
  CFlyNinja* LeftLeg;
  CKatannaNinja* RightLeg;
  CInvisibleNinja* Body;

  // default constructor
  public CSuperNinja() { 
    // -> there is no rule to call composed classes
    LeftArm = new CStarNinja();
    RightArm = new CInvincibleNinja();
    LeftLeg = new CFlyNinja();
    RightLeg = new CKatannaNinja();
    Body = new CInvisibleNinja();
  }

  // default destructor
  public ~SuperNinja() { 
    // -> there is no rule to call composed classes
    delete LeftArm();
    delete RightArm();
    delete LeftLeg();
    delete RightLeg();
    delete Body();
  }

  // --> add all public methods from peers,
  // --> to main class
  public void throwStars() { LeftArm->throwStars(); }
  public void useKatanna() { RightLeg->useKatanna(); }  
  public void becomeVisible() { Body->becomeVisible() }  
  public void becomeInvisible() { Body->becomeInvisible() }
  public void fly() { LeftLeg->fly() }  
  public void land() { LeftLeg->land() }
  public void turnToStone() { RightArm->turnToStone(); }  
  public void turnToHuman() { RightArm->turnToHuman(); }
} // class

, , , , .

.

0

, . , ?

, RedNinja - , . , Ninja, , Ninja RedNinja. .

0
source

A dirty solution, if you just have to have multiple inheritance, uses something like dynamic proxies in Java .

But I think that you are probably programming in C #, and this is a question of language agnostic, so here comes the language agnostic answer: look at composite and factory , which should give you some ideas.

In addition, it may not be necessary to pass everything in the constructor. Check out the IoC pattern .

-1
source

All Articles