Help with Prototype pattern ontop of composite pattern

Started by
10 comments, last by Scythen 14 years, 4 months ago
I have a set of classes all derived from one class "Modual" A Modual object contains a list of other Modual objects, AKA the composite pattern. Each of these Modual objects always of a type derived from Modual so as to provide different functionality. No I am trying to implement the prototype pattern to make copies of entire object structures. In fact I've been successful in this. The problem is that I want a some what cleaner solution. I have two functions, Clone and Copy. Copy is implement in the base class Modual and is responsible for recursively walking the composite structure and creating an duplicate structure. Clone is implemented in each derived class and simply returns a new object of the derived type. What I want is to not have to have two functions and to only implement Copy in the base class. The only trouble I'm having here is how to I make a new object of the derived type from with in the base class? I striped out a lot of extra code from this example because its really huge and most of it is unrelated to the question at hand.

namespace Mhz
{
    public abstract class Modual
    {
        protected static int stepsPerSecond = 44100;
        protected static double deltaT = 1.0 / stepsPerSecond;
        protected static double TwoPI = 2.0 * System.Math.PI;
        public System.Collections.Generic.List<Modual> Inputs;
        public double value;
        bool Processing, Copying;

        public Modual()
        {
            Inputs = new List<Modual>();
            Processing = false;
            Copying = false;
            value = 0.0;
        }

        protected abstract Modual Clone();
        public Modual Copy()
        {
            Modual T = null;
            if (!Copying)
            {
                Copying = true;
                T = Clone(); // <- This is implemented in each derived class and returns a new object of the derived type. See below definition.
                T.value = value;
                foreach (Modual M in Inputs)
                {
                    T.Inputs.Add(M.Copy());
                }
                Copying = false;
            }
            return T;
        }
       

        public void process()
        {
            if (!Processing)
            {
                Processing = true;
                foreach (Modual Mdl in Inputs)
                    Mdl.process();
                //if (In != null) In.process();
                //if (Mod != null) Mod.process();
                Processing = false;
            }
        }
        virtual public void ConectIn(ref Modual con)
        {
            Inputs.Add(con);
        }
        
    }

    
    public class Dial : Modual
    {
        override protected Modual Clone() { return (Modual)new Dial(); } // <- I want to avoid the need to have one of these in each derived class. 
        override public void process()
        {
        }
    }

    public abstract class SignalGen : Modual
    {
        protected double Theta = 0;
        protected double Hz = 100;

        override public void process()
        {
            base.process();
            Hz = Math.Abs(Inputs[Inputs.Count - 1].value);
            Theta += (deltaT * Hz * TwoPI);
            if (Theta >= TwoPI) Theta -= TwoPI;
        }
    };

    public class SinWave : SignalGen
    {
        override protected Modual Clone() { return (Modual)new SinWave(); }
        override public void process()
        {
            base.process();
            value = Math.Sin(Theta);
        }
    };

    public class SawWave : SignalGen
    {
        override protected Modual Clone() { return (Modual)new SawWave(); }
        override public void process()
        {
            base.process();
            value = -1.0 + (Theta / TwoPI * 2.0);
        }
    }

    public class ISawWave : SignalGen
    {
        override protected Modual Clone() { return (Modual)new ISawWave(); }
        override public void process()
        {
            base.process();
            value = 1.0 - (Theta / TwoPI * 2.0);
        }
    }

    public class TiangleWave : SignalGen
    {
        override protected Modual Clone() { return (Modual)new TiangleWave(); }
        override public void process()
        {
            base.process();
            if (Theta < System.Math.PI)
                value = -1.0 + (Theta / System.Math.PI * 2);
            else
                value = -1.0 + ((TwoPI - Theta) / System.Math.PI * 2);
        }
    }

    public class SquareWave : SignalGen
    {
        double DutyCycle;
        override protected Modual Clone() { return (Modual)new SquareWave(); }
        public override void process()
        {
            base.process();
            //if (In != null) DutyCycle = In.value; else DutyCycle = .5;
            if (Inputs.Count > 1) DutyCycle = Inputs[0].value; else DutyCycle = .5;
            if (Theta < DutyCycle * TwoPI) value = 1.0;
            else value = -1.0;
        }
    }
    
    class Adder : Modual
    {
        override protected Modual Clone() { return (Modual)new Adder(); }
        override public void process()
        {
            base.process();
            value = 0;
            foreach (Modual I in Inputs)
            {
                value += I.value;
            }
        }
    }
    class Inverter : Modual
    {
        override protected Modual Clone() { return (Modual)new Inverter(); }
        override public void process()
        {
            base.process();
            value = -Inputs[0].value;
        }
    }
public class DelayLine : Modual
    {
        System.Collections.Queue Doubles; //overide ConnectMod and set this guys size
        override protected Modual Clone() { return (Modual)new DelayLine(Doubles.Count); }
        public DelayLine(int Length)
        {
            Doubles = new System.Collections.Queue();
            for (int i = 0; i <= Length; i++)
            {
                Doubles.Enqueue((double)0.0);
            }
        }
        override public void process()
        {
            base.process();
            //Doubles.Count (int)Mod.value; Resize Queue (Streach or compress data)
            Doubles.Enqueue(Inputs[0].value);
            value = (double)Doubles.Dequeue();
        }
    }

}



Advertisement
The word is spelled "Module".

Quote:What I want is to not have to have two functions and to only implement Copy in the base class.


I don't think that's going to work, sorry.
No matter what, you are going to need to be able to create an object of a particular derived type given an instance of that type. If you don't want to provide that functionality with a virtual method then you could have a static factory method in the base class that takes a derived type and creates an object of the same type, but in order to do this you would need to add a virtual method that returns a unique (say) enum for each derived type or use runtime type information. Not sure what it would buy you to do this, and the factory method would be ugly, basically a big switch statement.
So is there no way to dynamically determine type at runtime and get different behavior....

Like instead of T = Clone(); using something T = (Modual)this.GetType();
Yes, I know that doesn't actually work.

 public Modual Copy()        {            Modual T = null;            if (!Copying)            {                Copying = true;                T = (Modual)this.GetType(); // <-Something like this, but that actually works.                T.value = value;                foreach (Modual M in Inputs)                {                    T.Inputs.Add(M.Copy());                }                Copying = false;            }            return T;        }
Quote:Original post by Grain
So is there no way to dynamically determine type at runtime and get different behavior....


I believe you're writing in Java, right? In Java the answer to your question is yes. I've never done it, so I can't provide details off the top of my head, but just google "java reflection example" or something like that.

No, actually it's C#.
I don't know much about C#, but you can probably do something analogous to reflection in Java. Let's see ... yeah, read this:

http://msdn.microsoft.com/en-us/library/ms173183(VS.80).aspx

[Edited by - jwezorek on December 4, 2009 5:51:32 PM]
Oh wow, that's it!

Instead of using T = Copy(); I can now do T = (Modual)System.Reflection .Activator.CreateInstance(this.GetType()):

Now I don't have to implement Copy() for all those subclasses. =)
Not sure if it’s important or not but I don’t see how you’re Clone/Copy functions actually "Clone" the object. How does the base class correctly copy the data members in the derived classes? Your implementation only initializes data members declared in the base class.
After thinking about it what you really want is to define copy constructors for all your classes and then implement clone like this:

public Base Clone(){    object[] param = new object[] { this };    return System.Activator.CreateInstance(this.GetType(), param) as Base;}

This topic is closed to new replies.

Advertisement