首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >可串行化/可覆盖的飞重系统使用什么设计/架构/模式?

可串行化/可覆盖的飞重系统使用什么设计/架构/模式?
EN

Software Engineering用户
提问于 2016-08-13 10:31:05
回答 1查看 485关注 0票数 0

我在玩火车游戏。我需要序列化每个级别使用哪一列火车。所以我可以简单地做:

代码语言:javascript
复制
public class Level {
    Track track;
    Train train;
    [...]
}

public class Train {
    Wagon[] wagons;
}

public class Wagon {
    float length;
    float weight;
}

//Example:
level = new Level (track, new Wagon (1f,2f));

但是,我需要有一种类型的马车,我可以选择。就像这样:

代码语言:javascript
复制
public class Wagon {
    float length;
    float weight;
    public static Wagon Small { get { return new Wagon (1f,2f); }}
    public static Wagon Big { get { return new Wagon (10f,20f); }}
}

//Example:
level = new Level (track, Wagon.Small);

这是可行的。但是,如果我想调整一个货车参数,我必须反序列化,修改和重新序列化每辆货车。

所以我想出了这个:

代码语言:javascript
复制
public enum WagonType {
    Small,
    Big
}

public class WagonParams {
    float length;
    float weight;
}

public class Wagon {
    WagonType type;
    WagonParams params { get { return WagonFactory.GetParams(type); }}
}

public WagonFactory {
    static WagonParams small;
    static WagonParams big;
    static WagonFactory () {
        small = new WagonParams (1f,2f);
        big = new WagonParams (10f,20f);
    }
    public static WagonParams GetParams (WagonType type) {
        switch (type) {
            case WagonType.Small: return small;
            case WagonType.Big: return big;
        }
    }
}

//Example:
level = new Level (track, new Wagon(WagonType.Small));

这看上去有点过火,但有效。

现在假设我想要一个SmallWagon,但是如果有更多的重量,我可以这样做:

代码语言:javascript
复制
public interface IOverrideWagonField {
    WagonParams Override (WagonParams params);
}

public class OverrideWeight : IOverrideWagonField {
    float weight;
    WagonParams Override (WagonParams params) {
        return new WagonParams (params.length, weight);
    }
}

public class Wagon {
    WagonType type;
    IOverrideField overrider;
    WagonParams params { get { return WagonFactory.GetParams(type,overrider); }}
}

public WagonFactory {
    static WagonParams small;
    static WagonParams big;
    static WagonFactory () {
        small = new WagonParams (1f,2f);
        big = new WagonParams (10f,20f);
    }
    public static WagonParams GetParams (WagonType type, IOverrideWagonField overrider) {
        switch (type) {
            case WagonType.Small: return overrider != null? overrider.Override(small) : small;
            case WagonType.Big: return overrider != null? overrider.Override(big) : big;
        }
    }
}

//Example:
level = new Level(track, new Wagon(WagonType.Small,null)); //Normal Wagon
level = new Level(track, new Wagon(WagonType.Small,new OverrideWeight (23f)); //Override weight

困扰我(除了复杂性)的是,每辆马车都使用内存作为他们可能不使用的IOverrideWagonField。

如果要覆盖多个字段,则系统会出现缺陷。它需要一个IOverrideWagonField数组,但它将为每个overrode字段创建一个新的对象。(重写()方法调用"new")

所以我觉得这个制度还很不完善。

你认为如何?你将如何实施这样一个系统?

EN

回答 1

Software Engineering用户

发布于 2016-08-13 23:24:46

看起来像一个过度工程的案例,我个人会保持它简单:对待所有的货车一样。

基本代码:

代码语言:javascript
复制
public class Wagon
{
    public float Length { get; set; }
    public float Weight { get; set; }
}

public class Train
{
    public List<Wagon> Wagons { get; set; }
}

public class Level
{
    public Train Train { get; set; }

    public static Level Deserialize(TextReader textReader)
    {
        if (textReader == null) throw new ArgumentNullException(nameof(textReader));
        var serializer = new XmlSerializer(typeof(Level));
        var deserialize = serializer.Deserialize(textReader);
        var level = deserialize as Level;
        return level;
    }

    public static void Serialize(TextWriter textWriter, Level level)
    {
        if (textWriter == null) throw new ArgumentNullException(nameof(textWriter));
        if (level == null) throw new ArgumentNullException(nameof(level));
        var serializer = new XmlSerializer(typeof(Level));
        serializer.Serialize(textWriter, level);
    }
}

演示:

代码语言:javascript
复制
public class Demo
{
    public Demo()
    {
        // some level
        var level = new Level
        {
            Train = new Train
            {
                Wagons = new List<Wagon>(new[]
                {
                    new Wagon
                    {
                        Length = 100.0f,
                        Weight = 100.0f
                    },
                    new Wagon
                    {
                        Length = 200.0f,
                        Weight = 200.0f
                    }
                })
            }
        };

        // serialize
        string xml;
        using (var writer = new StringWriter())
        {
            Level.Serialize(writer, level);
            xml = writer.ToString();
        }

        // deserialize
        using (var reader = new StringReader(xml))
        {
            var level1 = Level.Deserialize(reader);
        }
    }
}

您可以将Wagon子类如下所示:

代码语言:javascript
复制
public class SmallWagon : Wagon
{
    public SmallWagon()
    {
        Length = 10.0f;
        Weight = 10.0f;
    }
}

public class LargeWagon : Wagon
{
    public LargeWagon()
    {
        Length = 10000.0f;
        Weight = 10000.0f;
    }
}

但是您必须将这些类型包含在Wagon中,才能使序列化工作:

代码语言:javascript
复制
[XmlInclude(typeof(SmallWagon))]
[XmlInclude(typeof(LargeWagon))]
public class Wagon
{
    public float Length { get; set; }
    public float Weight { get; set; }
}

您可以通过自动收集它们并使用其他构造函数来减轻这种繁琐的工作:

代码语言:javascript
复制
var extraTypes = Assembly
    .GetExecutingAssembly()
    .GetTypes()
    .Where(s => s.BaseType == typeof(Wagon))
    .ToArray();
var serializer = new XmlSerializer(typeof(Level), extraTypes);

尽管如此,感觉还是像一种代码气味,因为现在有许多类型的货车:

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-16"?>
<Level xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Train>
    <Wagons>
      <Wagon xsi:type="SmallWagon">
        <Length>10</Length>
        <Weight>10</Weight>
      </Wagon>
      <Wagon xsi:type="LargeWagon">
        <Length>10000</Length>
        <Weight>10000</Weight>
      </Wagon>
      <Wagon>
        <Length>100</Length>
        <Weight>100</Weight>
      </Wagon>
      <Wagon>
        <Length>200</Length>
        <Weight>200</Weight>
      </Wagon>
    </Wagons>
  </Train>
</Level>

为了简化构建预置货车的过程,我要么使用一些静态类,要么使用一些原始构建器系统:

代码语言:javascript
复制
public static class WagonHelper
{
    public static Wagon CreateLargeWagon()
    {
        return new Wagon
        {
            Length = 10000.0f,
            Weight = 10000.0f
        };
    }

    public static Wagon CreateSmallWagon()
    {
        return new Wagon
        {
            Length = 10.0f,
            Weight = 10.0f
        };
    }
}

// or

public abstract class WagonBuilder
{
    public abstract Wagon Build();
}

public class LargeWagonBuilder : WagonBuilder
{
    public override Wagon Build()
    {
        return new Wagon
        {
            Length = 10000.0f,
            Weight = 10000.0f
        };
    }
}

坚持接吻原则,

现在,关于多次序列化,它没有什么问题,Unity3D经常这样做,以处理诸如在重新构建后重新加载程序集之类的事情。

票数 1
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/328315

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档