我认为了解语言设计者想要的默认实践以及他们针对语言改进的默认实践总是有用的,即使后来偏离了这些约定。在 Scala 中,所有字段都必须在声明它们的类的构造函数中初始化。这是一个重要的限制。辅助构造函数也受到限制。构造函数中的任何临时变量都需要放在内部方法或闭包中,以避免不需要的字段,这会使构造函数的主体看起来混乱。所有这些都不利于使用构造函数体。即使从超类分配给抽象变量时也需要覆盖 val/var 语法,这消除了为构造而使用派生类的一些优势。
伴随对象可以访问其类的所有字段。然而,对于构造来说,这并不是它可能首先出现的优势,因为所有字段都必须在类的构造函数中初始化。所以看起来很自然的做法是使用对象中的方法对类变量进行任何处理,为类中的每个不可变集合创建一个临时可变集合,listbuffer 是默认值,然后将所有值和集合传递到一个无形的构造函数。工厂可以在任何对象甚至类中,但也可以在伴随对象中,除非有充分的理由。对象不能接受类型参数,但如果需要,它们的工厂方法可以。当然,你可以拥有尽可能多的工厂方法,因为你需要准构造函数,它们可以重用任何常见的算法。
它是否正确?
为了响应示例的请求,这是我正在从 C# 移植到 Scala 的构造函数,请注意多个类型参数在 Scala 中消失了:
public class GridC : GridBase<HexC, SideC, UnitC, ISegC>
{
public Geometry<HexC, SideC, UnitC, ISegC> geomC { get; private set; }
internal GridC(Scen scen, int gridNum, int xDim, int yDim, int xOff, int yOff, Terr terr = Terr.Plain):
base(gridNum, scen, 10.0)
{
this.geomC = scen.geomC;
xIntLeft = xOff + 1;
yIntBottom = yOff;
xIntRight = xDim * 2 + 1 + xOff;
yIntTop = yDim * 2 + 2 + yOff;
Coodg hexCoodg;
for (int x = xOff; x < xDim * 2 + xOff; x += 2)
{
for (int y = yOff; y < yDim * 2 + yOff; y += 2)
{
if (x % 4 == y % 4)
{
hexCoodg = new Coodg(num, x + 2, y + 2);
HexC hexC = scen.hexCs.NewHexC(hexCoodg);
SideC sideC;
MiscStrat.sixDirn.ForEach(i =>
{
Coodg sideCoodg = hexCoodg + Cood.DirnTrans(i);
sideC = sides[sideCoodg];
if (sideC == null)
scen.sideCs.NewSide(hexC, i);
else
scen.sideCs.SetHex2(sideC, hexC, i);
});
}
}
}
}
创建上面的子类纯粹是为了给下面的基类提供一个构造函数,只是为了展示与构造相关的部分;
public class GridBase<HexT, SideT, UnitT, SegT> : IGridBase
where HexT : Hex where SideT : Side where UnitT : Unit where SegT : ISeg
{
public int num { get; private set; }
int IGridBase.num { get { return num; } }
IListsGeom<HexT, SideT, UnitT> iLists;
public HexList<HexT> hexs { get { return iLists.hexs; } }
public SideList<SideT> sides { get { return iLists.sides; } }
public Geometry<HexT, SideT, UnitT, SegT> geom { get; private set; }
public int xIntLeft { get; protected set; }
public int xIntRight { get; protected set; }
public int yIntBottom { get; internal set; }
public int yIntTop { get; internal set; }
public double scale { get; private set; }
protected GridBase(int num, IListsGeom<HexT, SideT, UnitT> iLists, double scale)
{
this.num = num;
this.iLists = iLists;
this.scale = scale;
}
}
构造函数创建一个简单的统一十六进制网格。需要使用完全不同算法的其他构造函数,并且将创建需要相关但更复杂算法的其他构造函数。我不是专家,但我的印象是工厂在 C# 中的使用要少得多。