【问题标题】:Access to private variables of Objects that are within a private array访问私有数组中的对象的私有变量
【发布时间】:2018-08-18 18:11:05
【问题描述】:

我想创建一个可以有多个菜单的 Restaurant 对象。每个菜单可以有多个类别,每个类别可以有多个项目。每件商品都有名称、价格和描述。

--Company--
  -Menu ONE-
  -Menu Name-
    -Category ONE-
       -Category Name-
       -Menu Item ONE-
         -Menu Item Name
         -Menu Item Price
         -Menu Item Description
       -Menu Item TWO-
    -Category TWO-
  -Menu TWO- 

没有构造函数、getter/setter 或方法的示例类。

拥有一系列菜单的公司

    public class Company
    {   
        // Class constants

        // Class variables
        private String companyName;   //  Stores company name
        private String hours;         //  Restaurant hours
        private String phoneNumber;   //  Restaurant phone number
        private Menu[] menuList;      //  Array of menu objects
        private int menuCount;        //  Number of menus in the array

     }

包含类别数组的菜单

    public class Menu
    {   
        // Class constants

        // Class variables
        private String menuName;           //  Name of Menu
        private Category[] categoryList;   //  Array of category objects
        private int categoryCount;         //  Number of categories in the array

     }

包含菜单项数组的类别

    public class Category
    {   
        // Class constants

        // Class variables
        private String categoryName;       //  Name of Menu
        private MenuItem[] menItemList;    //  Array of MenuItem objects
        private int menuItemCount;         //  Number of menu items in the array

     }

具有名称、价格和描述的单个订单项

    public class MenuItem
    {   
        // Class constants

        // Class variables
        private String name;        //  Name of Menu Item
        private float price;        //  Price of the Menu Item
        private String description; //  Description of the Menu Item

     }

在驱动程序类中,如果我只能访问公司的方法,我将如何更改菜单项中的任何内容?

我曾想过为每个私有数组项设置一个 getter,但是将 3 层向下挖掘到私有数组中似乎很难实现。不像Company.Menu.Category.MenuItem.editName(newName);那么简单

注意* 我对“应该使用链接列表或 ArrayList”的答案不感兴趣。程序要求需要基本数组。

如果我需要更清楚,或者您是否想要 SSCCE,请告诉我。

【问题讨论】:

  • 数据结构越复杂,ETL 越复杂。使用 getter/setter 并深入挖掘是您最好的选择。
  • 使用 getter/setter 访问私有成员变量

标签: java arrays private private-members


【解决方案1】:

我曾想过为每个私有项目数组设置一个 getter,但是 将 3 个级别深入到私有数组中似乎很难 实施。它不是那么简单 Company.Menu.Category.MenuItem.editName(newName);

实现起来并不难,但是连续调用 getter 是一种反模式,例如:

company.getMenu().getCategory().getMenuItem().editName(newName);

Demeter law 声明为:

每个单元应该只对其他单元有有限的了解:只有 与当前单位“密切”相关的单位。

每个单位都应该只和它的朋友交谈;不要和陌生人说话。

只与你的直系朋友交谈。

因此,要解决您的问题,您将不得不重构您的设计,以使您的对象从一个对象协作到另一个对象。

协作/级联方法

您可以定义一个editItemName() 方法,该方法由层次结构的每个对象依次调用。

Company可以定义方法如:

public void editItemName(String menuName, String categoryName, String itemName, String newName){ 
   Menu menu = findMenu(menuName);
   menu.editItemName(category, item, newName);
}

Menu可以定义方法如:

public void editItemName(String categoryName, String itemName, String newName){ 
   Category category = findCategory(categoryName);
   category.editItemName(item, newName);
}

Category可以定义方法如:

public void editItemName(String itemName, String newName){ 
   MenuItem item = findItem(itemName);
   item.editItemName(newName);
}

最后MenuItem可以定义如下方法:

public void editItemName(String newName){
   this.name = newName;
}

更直接的方法(如果合适)

传递这么多参数对客户来说可能很麻烦。 作为替代方案,如果Item 对象是唯一的(就equals() 而言)并且您可以从客户端获取它,您可以使事情变得更简单。 您可能只需要将MenuItem(叶子)中的方法定义为:

public void editItemName(String newName){
   this.name = newName;
}

您可以定义一个按标识符存储项目的地图:

Map<String, MenuItem> mapUniqueItems = new HashMap<>();
// add items in the map
mapUniqueItems.put("item1", new MenuItem(..));
mapUniqueItems.put("item2", new MenuItem(..));
// add items in the hierarchy as you actually do
...

然后你可以从它的 id 编辑一个项目,例如:

String itemIdentifier = ...;
MenuItem item = mapUniqueItems.get(itemIdentifier);
item.editItemName("new value");

【讨论】:

  • getter 和 setter 本身并不违反 demeter 法则。如果 A 调用 B.get 而 B 调用 C.get 那么一切都很好。当A调用C.get时,它违反了法律
  • 我指的是普通的吸气剂。要从 A 调用 C,您必须调用 A.getB().getC();你指的是A.getCfromB(),这不是一个愚蠢的吸气剂。它是一种执行更多逻辑的检索方法。
  • 我明白了...我以为 OP 说的是第二种
  • @avigil 实际上,OP 并不具体。所以我认为它是免费的。我进行了编辑以更具体地说明这一点。
  • @davidxxx 如果我这样做 MenuItem item = mapUniqueItems.get(itemId); 是否会执行对象的浅表副本以允许编辑其成员?
【解决方案2】:

如果您为必须从外部读取的成员创建 getter 方法,您必须深入挖掘以从 Menu 对象中获取所需的信息。这就是封装的重点。如果要重复这些操作,您可以创建一个辅助类/方法来管理数组的各个级别。

【讨论】:

    【解决方案3】:

    . 的链接是一种不好的做法,您可以执行以下操作来避免它

    在Company类中创建方法modifyMenu

      public class Company {
           public modifyMenu (int menuIndexToModify, int categoryIndex, MenuItem itemWithModification){
                menuList[menuIndexToModify].modifyMenuItem(categoryIndex, menuItemIndex, itemWithModification);
          }
      }
    

    Menu 类中创建方法modifyMenuItem

     public class Menu{
        public void modifyMenuItem(int categoryIndex, int menuItemIndex, MenuItem itemWithModification){
                  categoryList[categoryIndex].modifyMenuItem(menuItemIndex,itemWithModification);
        }
     }
    

    Category类中创建modifyMenuItem方法

    public class Category{
        public void modifyMenuItem(int menuItemIndex, MenuItem itemWithModification){
                menuItemList[menuItemIndex].modify(itemWithModification);
         }
     }
    

    克里特方法modify in MenuItem

     public void modify( MenuItem itemWithModification){
          this.name = itemWithModification.name
          // assign other stes similarly
     }
    

    现在您只需要调用方法 modifyMenu ,将参数传递给它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-02
      • 1970-01-01
      • 2019-02-14
      • 1970-01-01
      • 1970-01-01
      • 2015-09-25
      • 2012-05-09
      • 2018-11-02
      相关资源
      最近更新 更多