【问题标题】:Creating objects with very many optional fields创建具有很多可选字段的对象
【发布时间】:2014-10-12 14:34:15
【问题描述】:

我正在尝试将炉石卡牌重新创建为 Java 中的对象,但我无法以一种良好且高效的方式执行此操作。

所有卡片都有一些共同的属性,例如“名称”。但问题是要生成大约 300 张牌,每张牌可能具有或不具有大约 30 种不同的能力。现在,我是否必须创建一个基本卡类,将所有可能的能力设置为 false,然后将其所有特定能力参数设置为 true?这种方法似乎对所有 getter 以及某些能力需要指定的所有额外信息变得非常混乱......所以我的问题是是否有更好的方法来解决这类问题?

我想创建这些卡片对象,以便仅将特定能力“添加”为字段,但我不知道如何以一种好的方式做到这一点。

感谢您的帮助!

【问题讨论】:

  • 好的,那么我可以将每个能力创建为一个对象并添加到该列表中吗?这是个好主意,谢谢:)
  • 这是一个选项。您也可以使用枚举等。这取决于您实际需要的“能力”。

标签: oop architecture field performance


【解决方案1】:

就像 Dave 所说,在没有更多背景信息的情况下,要确定解决问题的最佳方法有点困难。但是,据我所知,您的问题是一个很常见的问题。对于常见问题,程序员通常会创建可以反复使用的高效解决方案,称为design patterns

并非在所有情况下都需要设计模式,因此请注意不要过度使用它们,但它们似乎可以在这里为您提供帮助。 Dave 提到的两种解决方案都可能有效,但是将每个能力都设为对象的问题在于,它要求您创建与能力一样多的类。此外,如果每个能力都是一个简单的变量,那么为所有能力创建类可能有点过头了,特别是因为如此多的类可能变得难以维护。尽管从接口继承这些能力在某种程度上有助于可维护性,但我认为在构建器模式中可能会找到更简单的解决方案。

我不会在这里详细解释,但这里有一个tutorial,看起来相当简单。它的基本目的是

对于您的特定示例,它看起来像这样:

    public class Card

    {

        private final String name;
        private final Ability soundAbility;
        private final Ability animationAbility;
        private final Ability customMessageAbility;
        private final String technology;

        // The constructor is private in this case to restrict instantiation to the builder.
        private Card(CardBuilder builder)
        {
            this.name = builder.name;
            this.soundAbility = builder.soundAbility;
            this.animationAbility = builder.animationAbility;
            this.customMessageAbility = builder.customMessageAbility;
            this.technology = builder.technology;
        }

        // Getters
        public String getName()
        {
            return this.name;
        }

        public Ability getSoundAbility()
        {
            return this.soundAbility;
        }

        // ... More getters and stuff ...

        @Override
        public String toString()
        {
            String text = "";
            text += this.name + ":";
            text += "\n\t" + this.soundAbility;
            text += "\n\t" + this.animationAbility;
            text += "\n\t" + this.customMessageAbility;
            text += "\n\tI have the ability of " + this.technology + "!";
            return text;
        }

        // Nested builder class
        public static class CardBuilder
        {

            private final String name;
            private Ability soundAbility;
            private Ability animationAbility;
            private Ability customMessageAbility;
            private String technology;

            public CardBuilder(String name)
            {
                this.name = name;
            }

            public CardBuilder soundAbility(Ability soundAbility)
            {
                this.soundAbility = soundAbility;
                return this;
            }

            public CardBuilder animationAbility(Ability animationAbility)
            {
                this.animationAbility = animationAbility;
                return this;
            }

            public CardBuilder customMessageAbility(Ability customMessageAbility)
            {
                this.customMessageAbility = customMessageAbility;
                return this;
            }

            public CardBuilder technology(String technology)
            {
                this.technology = technology;
                return this;
            }

            public Card build()
            {
                return new Card(this);
            }

        }

    }

然后运行程序:

package builderTest;

class BuilderMain
{

    public static void main(String[] args)
    {
        // Initialize ability objects.
        Ability a1 = new SoundAbility();
        Ability a2 = new AnimationAbility();
        Ability a3 = new CustomMessageAbility();

        // Build card
        Card card = new Card.CardBuilder("Birthday Card")
            .soundAbility(a1)
            .animationAbility(a2)
            .customMessageAbility(a3)
            .technology("Flash")
            .build();

        System.out.println(card);
    }

}

输出将类似于以下内容:

Birthday Card:
    I have the ability of sound!
    I have the ability of animation!
    I have the ability of customizing messages!
    I have the ability of Flash!

请记住,我在没有太多上下文的情况下工作,因此您需要的内容可能会大不相同。

【讨论】:

    【解决方案2】:

    虽然前面的回答都很好,但是这个Object创建还有另外一种实现方式

    有很多可选字段

    在处理数据库复杂性和Command design pattern 时,我发现自己处于类似情况。如您所知,某些表列值是强制性的 - 有些不是。我正在使用这个Effective Java book 对于这种情况。

    所以,这里有用的是Consider a builder when faced with many constructor parameters。这样做可以避免

    • 首先,伸缩构造函数模式(不能很好地扩展)- 它可以工作,但是当有很多参数时很难编写客户端代码,而且更难阅读。

    • 其次,JavaBeans 模式,这很好,但允许不一致并要求可变性。它在构建过程中可能处于不一致的状态,并且排除了使类也不可变的可能性。

    使用的 Builder 模式模拟在 Ada 和 Python 中发现的命名可选参数。与构造函数一样,builder 可以对其参数施加不变量。但是在将参数从构建器复制到对象之后检查它们是关键,并且它们被检查 对象字段而不是构建器字段。

    干杯。

    【讨论】:

      猜你喜欢
      • 2011-10-23
      • 2017-10-01
      • 2013-06-04
      • 1970-01-01
      • 2013-02-17
      • 2019-06-13
      • 1970-01-01
      • 1970-01-01
      • 2020-06-26
      相关资源
      最近更新 更多