문제

I'm trying to model a production system using a composite pattern. In short, the production system contains of facilities => factories => subsystems => workstations => activities => subactivities => elements. But I don't think I'd got it quite right, so I'd really appreciate some help!

First of all, I'm getting this strange errors saying "Activity doesn't contain a constructor that takes 0 arguments" for the "Workstation" class, and google that didn't give me anything useful to my problem (at least nothing I could apply).

Secondly I'm kind of just wondering if I have thought right at all? All the examples I've seen contains Interface as the parent class, is that something I should implement as well? Speaking of the examples, if anyone have a guide with an example similar to mine (and not just the regular Boss => Manager => Employee example with just three steps) I'd really appreciate it!

Here's the code I've produced so far:

class Element
{
    public int basicActivityIdx;   //GET - S[101], GS80 [102] etc PUT - AW[201], S[202], PD80[203] etc.. 

    public Element(int idx)
    {
        this.basicActivityIdx = idx;   //GET - S[101], GS80 [102] etc PUT - AW[201], S[202], PD80[203] etc.. 
    }

}

 class SubActivity : Element
{
    private string subActivityName;

    public void SubActivity(string name)
    {
        this.subActivityName = name;
    }


    private List<Element> childElements = new List<Element>();
    public void addChildElement(Element inElement)
    {
        childElements.Add(inElement);
    }

}

class Activity : SubActivity
{
    public string activityName;
    public int activityFrequency; // Index to the list of choises ([1]every cycle, [2]every batch, [3]periodically)

    public void Activity(string name, int idx)
    {
        this.activityName = name;
        this.activityFrequency = idx;
    }

    private List<SubActivity> childSubActivities = new List<SubActivity>();
    public void addSubActivity(SubActivity inSubActivity)
    {
        childSubActivities.Add(inSubActivity);
    }

}

class Workstation : Activity
{
    private string workstationName;
    public void Workstation(string name)
    {
        workstationName = name;
    }


    private List<Activity> childActivities = new List<Activity>();
    public void addActivity(Activity inSubActivity)
    {
        childActivities.Add(inSubActivity);
    }
}

class SubSystem : Workstation
{
    public string subSystemName;

    public void SubSystem(string name)
    {
        this.subSystemName = name;
    }

    private List<Workstation> childWorkstations = new List<Workstation>();
    public void addWorkstation(Workstation inWorkstation)
    {
        childWorkstations.Add(inWorkstation);
    }
}

class Factory : SubSystem
{
    public string factoryName;
    public void Factory(string name)
    {
        this.factoryName = name;
    }

    private List<SubSystem> childSubSystems = new List<SubSystem>();
    public void addSubSystem(SubSystem inSubSystem)
    {
        childSubSystems.Add(inSubSystem);
    }
}

class Facility : Factory
{
    public string facilityName;

    public void Facility(string name) 
    {
        this.facilityName = name;
    }

    private List<Element> childFactories = new List<Element>();
    public void addFactory(Factory inFactory)
    {
        childFactories.Add(inFactory);
    }

}
도움이 되었습니까?

해결책

First, concerning to the design pattern itself. The composite you have implemented isn't the same as the GOF Composite. You have made some kind a variant form of that. (I think this isn't what you expect.)

Second, the top level type Element (GOF -> Component) must not be an interface type, but it should be, since the derivations should (normally) come up with their own implementation. At least the top level type should be abstract. By using this approach, the sub classes don't need to maintain a list of references to the top level or ist parent type.


Just a pseudo source example:

abstract class Element
{
    protected int basicActivityIdx;   //GET - S[101], GS80 [102] etc PUT - AW[201], S[202], PD80[203] etc.. 
    protected string basicActivityName;

    protected Element(int idx, string name)
    {
        this.basicActivityIdx = idx;   //GET - S[101], GS80 [102] etc PUT - AW[201], S[202], PD80[203] etc.. 
        this.basicActivityName = name;
    }

    public abstract void addChild(Element child);
    public abstract void doSthOperation();
    // TODO -> Define further operations ...
}

// Maybe you won't need this. It just tells you that the current node doesn't have any children
class Leaf : Element{
    public void Leaf(int idx, string name) : base(idx, name){}

    public void addChild(Element child){
        throw new SystemException("A leaf isn't allowed to have children!");
    }

    public void doSthOperation(){
        Console.WriteLine("I am the last node in the hierarchy!");
    }
}

class Activity : Element
{
    private List<Element> children;
    public void Activity(int idx, string name) : base(idx, name)
    {
        this.children = new List<Element>();
    }

    public void addChild(Element child){
        this.children.add(child);
    }

    public void doSthOperation(){
        Console.WriteLine("I am a concreate instance of Activity!");
    }
}

class SubActivity : Activiy{
    // This implementation doesn't have to maintain a list of top level elements, since its base class already is doing this!
    public void SubActivity(int idx, string name) : base(idx, name) { }

    public void addChild(Element child){
        base.addChild(child); 
        // Or implement its own behavior how children are added to the list.
        // Maybe you want to add any specific data to the the attached child here.
    }

    public void doSthOperation(){
        Console.WriteLine("I am a concreate instance of SubActivity!");
    }
}

A further example which may suite your needs more, since a SubSystem must not be a Factory and a Factory must not be a Facility:

// With this approach the element can never be a pure abstract class (interface)!
// The benefit of this version, in contrast to the previous one, is that the design
// of the software can be easily adapted to the real worlds structure, since it is defined
// dynamically, instead of staticaly like in the example above.
abstract class Element
{
    protected int id;   //GET - S[101], GS80 [102] etc PUT - AW[201], S[202], PD80[203] etc.. 
    protected string name;
    // This instance itself maintains a list of self references
    protected List<Element> children;

    protected Element(int id, string name)
    {
        this.children = new List<Element>();
        this.id = idx;   //GET - S[101], GS80 [102] etc PUT - AW[201], S[202], PD80[203] etc.. 
        this.name = name;
    }

    public void addChild(Element child){
        this.children.add(child);
    }

    public virtual void doSthOperation(){
        Console.WriteLine("I am the element instance itself!");
    }
    // TODO -> Define further operations ...
}

// Maybe you won't need this. It just tells you that the current node doesn't have any children
class Leaf : Element{
    public void Leaf(int id, string name) : base(id, name){}

    public void addChild(Element child){
        throw new SystemException("A leaf isn't allowed to have children!");
    }

    public void doSthOperation(){
        Console.WriteLine("I am the last node in the hierarchy!");
    }
}

class Facility : Element
{
    public void Facility(int id, string name) : base(id, name)

    public void doSthOperation(){
        Console.WriteLine("I am a concreate instance of Faciltiy!");
    }
}

class Factory : Element{
    public void Factory(int id, string name) : base(id, name) { }

    public void doSthOperation(){
        Console.WriteLine("I am a concreate instance of Factory!");
    }
}

class SubSystem : Element{
    public void SubSystem(int id, string name) : base(id, name) { }

    public void doSthOperation(){
        Console.WriteLine("I am a concreate instance of SubSystem!");
    }
}

다른 팁

As you inheriting from Activity in Workstation and Activity has no default constructor taking zero arguments, then you have to use one of the contstructors available, Activity(string name, int idx), or add a parmeterless constructor.

public void Workstation(string name) : base(name, -1)
{
    workstationName = name;
}

Where base is the class you are inheriting from, you need to forward theese properties to the base class in order to instanciate it. -1 is the idx parameter and name is the

It seems that all your classes are inheriting from Element I suggest you add an the ID parameter to all your subclasses in the constructor and add an Name property to the Element class. Then you don't have to declare a new "Name" property for all your subclasses.

class Element
{
    protected int _idx;  
    protected string _name; 

    public int Idx { get { return _idx; } }
    public string Name { get { return _name; } }


    public Element(int idx, string name)
    {
      _idx = idx;   
      _name = name;
    }
}

Then you add a constructor to all your subclasses and just forward parameters to the base class.

class SubActivity : Element {

   public SubActivity(int idx, string name) : base(idx, name)
   {
   }

 }

When you define a class in c# and do not explict create a constructor then the compiler will do it for you. But as soon you do define a constructor, then you will only have that constructor.

A class that has no constructor taking zero arguments (a default constructor) must be instanciated with the required parameters, thus using the base keyword in your sub class to pass the required parameters to the base class.

Pseudo Example:

class Foo{}

// Foo be instanciated by the "automatic" default constructor

new Foo()

class Boo{
   Boo(string name){}
}

// Boo cannot be instanciated without the required parameter: name

Boo() 
// will give you an compilation error: Boo does not contain a constructor taking zero arguments

Boo("the boo") // will work finem thus the parameter: name, is supplied

// the same goes for inheritance

class Moo : Boo {}
// in order to instanciate Moo which IS Boo by inheritance you need to get the required arguments passed from Moo to Boo

This can be solved by either modifying Boo manually adding a default constructor or adding a constructor in the sub class Moo which take the 'name' parameter and pass it on to the base class (Boo) with the base keyword. Which one suits best it's up to what you are designing.

Alt 1. (modifing base class)

class Boo{
  Boo(){ ... _name = "default name"; ... } // define default constructor
  Boo(string name){}
}

Alt 2. (modifying the sub class)

class Moo : Boo {
  Moo(string name) : base(name){}
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top