Reputation: 336
Starting out with a basic class called Weapon, I intended it to be polymorphic as follows:
public class Weapon
{
// Some code..
}
public class MachineGun : Weapon
{
// Extend the base code..
}
These classes define the basic functionality, however they do not contain any code to draw the weapon. This drawing only needs to be added in the Client application, the Server simply uses the MachineGun class without needing visualization.
public class DrawableWeapon : Weapon
{
// Adding draw calls and properties
}
public class DrawableMachineGun : DrawableWeapon
{
// The problem:
// You have no access to the properties of the original MachineGun here
}
// or..
public class DrawableMachineGun : MachineGun
{
// Same problem, only now you miss properties of the DrawableWeapon
}
The problem is losing either functionality of the MachineGun() class or the DrawableWeapon() class, since C# has no multiple inheritance.
Defining the Weapon class as an interface gave no succes either, you can't define methods in an interface which is exactly what I need to reduce code.
The only (partial) solution I found was for methods: define them in a seperate static class and on each method call in a drawable class, call this static method as well. This still leaves out all properties, and leads to long method calls..
What is the best option to implement this nicely? Is there a better programming pattern to use in this case?
Upvotes: 1
Views: 528
Reputation: 7364
Yes. You can use a Decorator pattern:
public class Weapon
{
public virtual void Shot()
{
// Some code...
}
}
public class MachineGun : Weapon
{
public override void Shot()
{
// Extend base code...
}
}
public class DrawableWeapon : Weapon
{
Weapon mWeapon;
public override void Shot()
{
mWeapon.Shot();
}
// Adding draw calls and properties
}
Upvotes: 4
Reputation: 326
You can use generics and the decorator pattern to implement the DrawableWeapon
public class DrawableWeapon<T> : Weapon where T : Weapon
{
T _weapon;
public void Shot()
{
_weapon.Shot();
}
}
In this way you get a distinct DrawableWeapon class for each weapon you implement.
Upvotes: 0
Reputation: 3302
Another approach, using method injection to allow multiple drawer implementations, while you can add IDrawable where needed.
interface IDrawable {
Draw(WeaponDrawer)
}
class DrawableWeapon : Weapon, IDrawable {
Draw(WeaponDrawer wd){
wd.Draw(this);
}
}
class WeaponDrawer {
Draw(Weapon weapon){
//drawing logic here
}
}
Upvotes: 0
Reputation: 6222
Perhaps a different way of looking at this is to create a composition of different classes rather than use classic OO inheritence. This emphasises the use of interfaces rather than class hierarchies where general purpose code is not inherited but consumed. Example;
interface IDrawer
{
void Draw();
}
class WeaponDrawer : IDrawer // class carries out the drawing of a weapon
class Weapon : IDrawer
{
private IDrawer : weaponDrawer = new WeaponDrawer();
// Delegate the draw method to a completely different class.
public void Draw()
{
this.weaponDrawer.Draw();
}
}
This follows the SOLID principles by keeping the definition of Weapon seperate from the function of drawing the weapon. (You could of course use an IOC container instead of the "= new WeaponDrawer()"). You end up with a set of single purpose classes instead of a complex inheritence hierarchy - it looks like more code, but you might well find that the design is clearer and more maintainable.
Upvotes: 0
Reputation: 11549
You can use decorator pattern to extend your classes without inheritance. It is good to remember favor object composition over inheritance principle for this kind of polymorphism problems.
interface Weapon : Weapon {
void Fire();
}
class MachineGun : Weapon {
public override void Fire() {
for (int i = 0; i < 5; i++) {
// Do something
}
}
}
class HandGun : Weapon {
public override void Fire() {
// Do something
}
}
abstract class WeaponDecorator : Weapon {
protected Weapon weapon;
public WeaponDecorator(Weapon weapon) {
this.weapon = weapon;
}
// Implement methods by calling this.weapon's method
public virtual void Fire() {
weapon.Fire();
}
}
class DrawableWeapon : WeaponDecorator {
public DrawableWeapon (Weapon weapon) : base(weapon) {
}
public override void Fire() {
PlayShakingEffect();
base.Fire();
}
private void PlayShakingEffect() {
}
}
Having this code we can make any type of Weapon
drawable. Note all weapons are still instance of Weapon
.
Weapon machineGun = new MachineGun();
Weapon handGun = new HandGun();
Weapon drawableMachineGun = new DrawableWeapon(new MachineGun());
Weapon drawableHandGun = new DrawableWeapon(new HandGun());
Upvotes: 0