1

I've inherited a large codebase and I'm trying to implement some new functionality into the framework. Basically, in order to do it the "right" way, I would have to modify the entire structure of the framework. since I'm not the guy who designed the framework, nor am I a mind reader, doing so probably isn't going to happen (although I would really love to redesign it all from scratch myself).

So in order to do what I want, I'm trying to implement a decorator pattern, of sorts. This answer from maliger suggests that what I'm doing below is perfectly valid. However, mono doesn't seem to like it; it complains that T cannot be derived from when I declare HappyDecorator

Please forgive the overly simplistic example, but it gets the point across.

public class HappyObject
{
    public virtual void print()
    {
        Console.WriteLine ("I'm happy");
    }
}

public class VeryHappyObject : HappyObject
{
    public override void print()
    {
        Console.WriteLine ("I'm very happy");
    }

    public void LeapForJoy()
    {
        Console.WriteLine("Leaping For Joy!");
    }
}

public class SuperHappyObject : VeryHappyObject
{    
    public override void print()
    {
        Console.WriteLine ("I'm super happy!");
    }

    public void DieOfLaughter()
    {
        Console.WriteLine("Me Dead!");
    }
}

public class HappyDecorator<T> : T where T : HappyObject
{
    public string SpecialFactor { get; set; }

    public void printMe()
    {
        Console.WriteLine (SpecialFactor);
        print();
    }
}
class MainClass
{
    public static void Main (string[] args)
    {
        HappyDecorator<HappyObject> obj = new HappyDecorator<HappyObject> ();
        obj.SpecialFactor = Console.ReadLine();
        obj.printMe();
    }
}
Community
  • 1
  • 1
audiFanatic
  • 2,296
  • 8
  • 40
  • 56
  • 1
    Do you get an error? Or how does it not behave as expected? – mason Mar 10 '15 at 23:55
  • this isn't the way to follow the decorator pattern. obj obect should get a HappyDecorator in his constractor. – ro-E Mar 10 '15 at 23:57
  • You can't inherit generic type parameter and that's exactly what error message says for your code sample. What part of it don't you understand? – MarcinJuraszek Mar 11 '15 at 00:01
  • Sounds like you should get rid of all that cr_p and use `System.Action` instead. Creating classes just to hold functions like this is called *"Execution in the Kingdom of Nouns"* and is an illness that affects mostly badly designed archaic languages such as java, whereas C# has proper features to deal with this without having to create endless class hierarchies. – Federico Berasategui Mar 11 '15 at 00:02
  • You can't inherit `T`. Either inherit `HappyObject`, or inject and wrap `T`. I'd go with the later. – abatishchev Mar 11 '15 at 00:05
  • @mason yes, I do get an error. It says that HappyDecorator cannot inherit T – audiFanatic Mar 11 '15 at 01:42
  • @HighCore I agree completely, however, can you elaborate a bit more on how that will help? – audiFanatic Mar 11 '15 at 04:00

2 Answers2

3

You're typing HappyDecorator to T, but there's no instance of T to use inside that class.

public class HappyDecorator<T> where T : HappyObject
{
    private readonly T _instance;

    public HappyDecorator(T instance)
    {
        _instance = instance;
    }

    public string SpecialFactor { get; set; }

    public void printMe()
    {
        Console.WriteLine(SpecialFactor);
        _instance.print();
    }
}

Another alternative is to structure it like this with a generic method instead of a generic class. It's not really a decorator then though:

public class HappyDecorator
{
    public string SpecialFactor { get; set; }

    public void printMe<T>(T instance) where T : HappyObject
    {
        Console.WriteLine(SpecialFactor);
        instance.print();
    }
}

And call like:

        HappyDecorator obj = new HappyDecorator();
        obj.SpecialFactor = Console.ReadLine();
        obj.printMe(new HappyObject()); 
CRice
  • 12,279
  • 7
  • 57
  • 84
  • `HappyDecorator` inherits `T` in OPs code sample, so it's the instance itself. – MarcinJuraszek Mar 10 '15 at 23:58
  • 2
    Except that is incorrect syntax and does not compile. So should it inherit HappyObject then, in which case the benefits of generics are gone. – CRice Mar 11 '15 at 00:02
  • I know it's not a valid syntax. I'd just love your answer to state that before you suggest ways of work around it :) – MarcinJuraszek Mar 11 '15 at 00:10
  • The second one is definitely not what I want to do, the object must inherit `HappyObject` somehow and must be able to be used as such. The first solution poses a problem because if I were to pass in a `VeryHappyObject` or a `SuperHappyObject` to the constructor, I'll lose access to special fields contained within those two objects. Unfortunately, my example doesn't reflect that properly; I'll edit it to make it a tad clearer. – audiFanatic Mar 11 '15 at 13:19
  • What about ditching the HappyDecorator class, moving SpecialFactor and printMe to the base class, and just creating the correct instance you care about? Otherwise the decorator class will need to expose T so its methods can be called. – CRice Mar 11 '15 at 14:04
0

I think this is what you are trying to do:

    public interface IhappyObject
    {
        void Print();
    }

    public class HappyObject : IhappyObject
    {
        private IhappyObject obj;

        public HappyObject(IhappyObject obj)
        {
            this.obj = obj;
        }

        public void Print()
        {
            obj.Print();
        }
    }

    public class VeryHappyObject : IhappyObject
    {
        public void Print()
        {
            Console.WriteLine("I'm very happy");
        }
    }

    public class SuperHappyObject : IhappyObject
    {
        public void Print()
        {
            Console.WriteLine("I'm super happy!");
        }
    }

    static void Main(string[] args)
    {
        HappyObject obj = new HappyObject(new SuperHappyObject());
        obj.Print();
    }
ro-E
  • 279
  • 1
  • 5
  • 16
  • eh, not exactly. The reason I didn't opt for a traditional decorator pattern is because I want to avoid having to explicitly wrapping methods. Of course, the actual code (I refuse to call this abomination my own work) is much more complex than the example I provided. – audiFanatic Mar 11 '15 at 13:14
  • So for instance, suppose `VeryHappyObject` and `SuperHappyObject` have parameters not contained in the interface `IHappyBbject`. If I'm understanding your implementation correctly, Concretely, suppose they had the methods `LeapForJoy()` and `DieOfLaughter()` respectively (but not both). Then I'd have to define both of those functions in the interface, which isn't exactly what I want to do, because again, in actuality these objects are much more complex than I'm making them out to be and doing so is a real PITA. – audiFanatic Mar 11 '15 at 13:14