2

我有几个类都继承自同一个Shape类。当我创建一个新形状时,我希望它具有随机形状。我想这样做的方法是创建一个包含所有构造函数的链接的列表,当我需要创建一个新形状时,我将从列表中获取一个随机构造函数并使用它来构造我的形状。我尝试以休闲方式创建列表,但出现错误:

List<Action> constList = new List<Action>();
constList.Add(SShape());
constList.Add(OShape());
constList.Add(LShape());

构造Shape函数定义为:

class Shape
{
    public Shape(PlayGrid grid, Color color)
    {
        ...
    }
    ...
}

每个子形状的构造函数定义如下:

class IShape : Shape
{
    public IShape(PlayGrid grid, Color color) : base(grid, color)
    {
    ...
    }
...
}

构造列表的正确方法是什么,使用列表中的构造函数的方法是什么?

承包商还需要获得在不同形状之间变化的参数。

4

6 回答 6

5

这个概念可以工作,你只是有生成委托的语法错误,你想要一个Func<PlayGrid, Color, Shape>不是Action

var constList = new List<Func<PlayGrid, Color, Shape>>();
constList.Add((pg, c) => new SShape(pg, c));

PlayGrid playgrid = /* however you get this */;
Color color = /* however you get this */;
var shape = constList[randomIdx](playgrid, color);
于 2013-03-22T12:25:54.980 回答
2

你可以这样做:

public class ShapeFactory()
{
   //list of shape constructor functions
   private List<Func<Shape>> constructors;

   //static initalizaton of the constructor list
   static ShapeFactory()
   {
      constructors = new List<Func<Shape>>();
      constructors.Add( () => new OShape());
      constructors.Add( () => new SShape());
      constructors.Add( () => new LShape());
      ....
   }

   public static Shape CreateRandomShape()
   {
       int index = ...get random index somehow...
       return constructors[index]();
   }
}

并在代码中使用它

Shape randomShape = ShapeFactory.CreateRandomShape();
于 2013-03-22T12:31:55.817 回答
0

我相信您想为所有形状创建一个接口(可能是“IShape”),然后使用工厂来实例化它们(此时您可以随机实例化任何实现您的 IShape 接口的类型。)

于 2013-03-22T12:26:02.993 回答
0

以这种方式创建随机对象的责任不应该是对象本身的行为。我建议你创建一个工厂来管理这个。您的工厂可以生成构造函数调用列表(或预缓存对象),然后在其 create 方法中提供其中之一。您的工厂应该返回构造的对象(可能作为接口,如 IShape),而不是调用以创建对象的操作。这样,如果您的工厂需要注入依赖项或设置其他值,它可以这样做并管理对象的构造。

另外,如果那是 .NET Action 类,我猜你的 Shape 类不会从它继承,但从你的问题中不清楚“我得到错误”是什么。

这是关于在您的基类中拥有 GetRandomShape() 方法的评论。您不希望这样,因为您的基类知道并依赖于它的子类,这违反了 OO 设计实践。

于 2013-03-22T12:26:44.270 回答
0

您可以将类的类型保存到列表中并用于Activator.CreateInstance(Type)选择新实例。

或者您创建一个 Shape 类型的列表,为每个类添加一个实例,然后使用该.Clone()方法获取一个新实例。

或者你实现一个工厂模式

于 2013-03-22T12:27:52.180 回答
0

这是您开始的内容的延续。它使用反射来调用构造函数。初始列表是类型列表,而不是操作列表。

class Program
    {
        static void Main(string[] args)
        {


            //register the types
            List<Type> types = new List<Type>() { typeof(OShape), typeof(PShape), typeof(RShape) };

            // randomly select one
            Type type = types[1];

            // invoke the ctor
            ConstructorInfo ctor = type.GetConstructor(/*optional param for ctor, none in this case*/ new Type[] {} );
            object instance = ctor.Invoke(new object[] {});

            // you can safely cast to Shape
            Shape shape = (Shape)instance; //this is a PShape!

        }
    }

    class Shape
    {
    }

    class OShape : Shape
    {
    }

    class PShape : Shape
    {
    }

    class RShape : Shape
    {
    }
}

接下来要考虑的是如何允许 Shape 的子类型接收参数。您需要一个工厂模式,即一个知道如何构造其他对象并将基于 - 例如 - 字符串的对象:

Shape s = Factory.GetShape("OShape", new[] object {4});

检查这个问题

于 2013-03-22T12:35:03.760 回答