【问题标题】:How can I avoid getters AND avoid hard coding the UI?如何避免 getter 并避免对 UI 进行硬编码?
【发布时间】:2011-04-11 06:41:19
【问题描述】:

我想在控制台上打印一个战士的描述,其中包括战士的力量和战士的武器,格式为This <description> warrior uses a <weapon> 例如:This strong warrior uses a butter knife

为了清楚起见编辑:我想这样做而不是通过使用 getter 或任何其他方法(如 toString)来向对象询问数据,这揭示了对象的内部实现。我也想在不将我当前的 UI(控制台)硬编码到对象本身的情况下做到这一点。

public class Warrior
{
  private String description;
  private Weapon weapon;

  public Room(String description, Weapon weapon)
  {
    this.description = description;
    this.weapon = weapon
  }
}

public class Weapon
{
  private String name;

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

避免吸气剂

我可以通过对 UI 进行硬编码来避免 getter:

//Warrior class
public void display() 
{
  String.out.println("This " + description + " warrior uses a ");
  weapon.display();
}

//Weapon class
public void display() 
{
  String.out.print(name);
}

避免硬编码的 UI

我可以通过使用 getter 来避免硬编码的 UI:

//Warrior class
public String getDescription() 
{
  return "This " + description + " warrior uses a " + weapon.getName();
}

//Weapon class
public String getName() 
{
  return name;
}

是否可以同时避免两者?在上面的例子中我该怎么做?

注意:对于一些初步答案,getter 不是遵循命名约定getSomeFieldName 的方法。因此,将getSomeFieldName 重命名为aMethodThatIsNotPrefixedByGet 不是解决方案。 getter 是一种将私有数据从对象传递到调用它的作用域的方法。

为了完全清楚,我在这里试图处理的问题是与数据封装有关(因为这个问题被标记了)。如何防止将数据传递给不需要知道该数据的对象,同时仍然避免对 UI 进行硬编码?

此外,基于onthesequestions,我不认为 toString 应该以许多答案所建议的方式使用。 toString 似乎是用于生成对象的文本表示以进行调试等,而不是用于返回任意输出,尤其不是用于返回依赖于应用程序的输出。

【问题讨论】:

  • 除了覆盖 toSting() 之外,没有真正的方法可以在不使用 getter 的情况下在 java 中获取对象的描述——这就是它们的用途。与动态属性访问相比,它们可能看起来很繁琐,承认
  • @kostja 感谢您的评论!我同意除了使用 getter 之外没有其他方法可以获取对象的描述。但是,我不想“获得对象的描述”。我想看看是否可以告诉一个对象显示其描述而无需对 UI 进行硬编码。
  • 您可能已经注意到,您的问题 getters 是 OO 的对立面。一些著名的编码员对此有一篇很好的发人深省的文章/博客(不记得是哪一篇)。当然,重要的是对象如何相互交互。如果他们使用 getter 进行交互,那么就不是 OO。使用和过度使用 getter 的人根本不会得到 OO。如果您希望您的程序是“OO”,那么您就无法真正避免“对 UI 进行硬编码”,原因很简单:在设计良好的 OO 程序中,对象知道如何绘制自己。
  • 当然你可以让你的对象知道如何根据他与之交互的对象来绘制自己。例如,在游戏中,您可能让您的对象知道如何将自己的绘图命令发送到您的主绘图管道,并且还知道如何在例如一个微小的“迷你地图”以及例如一个文本控制台上绘制自己.这完全是关于对象如何与其他对象交互,当它是 OO 时,就没有争议了:对象应该知道如何绘制自己。
  • 想象一下你有一个方法displayMeUsingLanguageAndColorScheme(lang,scheme)...这有点牵强,但这就是想法:那个?好吧,不多,您仍然可以使您的“硬编码 UI”适应周围的对象(语言、配色方案等)。

标签: java encapsulation getter tell-dont-ask


【解决方案1】:

是的,去i18n

messages.properties
displayMessage = This {0} warrior uses a {1}

messages.properties_en_US
displayMessage = This {0} warrior uses a {1}

public static String getString(String key, Object... params  ) {
        try {
            return MessageFormat.format(RESOURCE_BUNDLE.getString(key), params);
        } catch (MissingResourceException e) {
            return '!' + key + '!';
        }
}

【讨论】:

    【解决方案2】:

    我会在 Warrior 和 Weapon 中重写 toString() 方法,因为这个方法自然会返回一个对象的字符串表示。然后我会创建一个专门用于创建描述的类,例如DescriptionMaker,并在其中创建一个方法:

    String createDescription(Warrior warrior, Weapon weapon)
    {
        return "This " + warrior + " uses a " + weapon;
    }
    

    然后可以将这个方法的返回值打印到控制台。此外,可以在 DescriptionMaker 类中应用内化。

    【讨论】:

      【解决方案3】:

      在这种情况下,getter 对我来说似乎是一个很好的做法,因为它们允许您将数据(Warrior 和 Weapon 类)与 UI(调用 getter 并创建描述字符串、小部件、html 代码等)分开。 .但是我不会让 Warrior getter 创建字符串,它只会返回战士描述,UI 类会创建字符串(您建议在示例中使用的 Warrior.getDescription() 方法)。

      【讨论】:

        【解决方案4】:

        你可以在你的 Warrior 类中重写 toString 来实现它。

        public String toString() {
        
        
        return "This " + this.description + " warrior uses a " + weapon.toString();
        
        }
        

        覆盖 toString inWeapon 以返回名称;

        作为

        public String toString() {
        
            return this.name;
        
            }
        

        你可以直接打印为

        System.out.println(warrior);
        

        【讨论】:

          【解决方案5】:
          public Interface IWarriorView {
            public void display(String description, Weapon weapon);
          }
          
          public Interface IWeaponView {
            public void display(String name);
          }
          
          public class WeaponViewImpl {
            public void display(String name) {
              System.out.println(name);
            }
          }
          
          public class WarriorViewImpl {
            public void display(String description, Weapon weapon) {
              System.out.println("This " + description + " warrior uses a ");
              weapon.display(new WeaponImpl());
            }
          }
          
          // Warrior class
          public String display(IWarriorView view) {
            view.display(description, weapon);
          }
          
          // Weapon class
          public String display(IWeaponView view) {
            view.display(name);
          }
          

          【讨论】:

            【解决方案6】:

            如何结合两者:

            //Warrior class
            public String display() 
            {
              return "This " + description + " warrior uses a "+weapon.display();;
            
            }
            
            //Weapon class
            public String display() 
            {
              return name;
            }
            

            【讨论】:

              猜你喜欢
              • 2020-05-28
              • 1970-01-01
              • 2022-10-31
              • 1970-01-01
              • 1970-01-01
              • 2021-09-13
              • 1970-01-01
              • 1970-01-01
              • 2018-11-19
              相关资源
              最近更新 更多