建模类层次结构

时间:2017-04-27 11:01:16

标签: java oop design-patterns data-modeling

我目前正在为类层次结构建模,因此想要检查是否有人有更好的方法来执行此操作。问题如下:

我有一个菜单项,里面有id和图标。然后我也可以有菜单项,其他子菜单项(但不是同时的图标)。它基本上是子菜单项的容器,但也有id作为真正的菜单项。目前的模型是这样的:

class SubMenuItemOrderNumber{}
class MenuItemTypeId{}
class MenuIconId{}
class MenuIcon{}

interface MenuItemWithoutSubItems{
    MenuItemTypeId getTypeId();
    List<MenuIcon> getIcons();
}

interface MenuItemWithSubItems{
    MenuItemTypeId getTypeId();
    Map<SubMenuItemOrderNumber, SubMenuItem> getOrderNumToSubMenuItem();
}

interface SubMenuItem{
    SubMenuItemOrderNumber getOrderNum();
    List<MenuIcon> getIcons();
}

interface Publishable{
    void suspend();
    void publish();
}

interface ControllableMenuItemWithoutSubItems extends MenuItemWithoutSubItems, Publishable{
    void control(MenuIconId iconId, String iconData);
}

interface ControllableMenuItemWithSubItems extends MenuItemWithSubItems, Publishable{
    void control(SubMenuItemOrderNumber orderNum, MenuIconId iconId, String iconData);
}

问题 - 似乎我可以使它更通用。只有我想到的是这种变化:

    enum EnumSubMenuItemOrderNumber implements SubMenuItemOrderNumber{
    ONLY_IF_MENU_ITEM_WITHOUT_SUB_ITEMS(0);
    private int num;
    EnumSubMenuItemTypeId(num id){
        this.num = num;
    }
    @Override
    public Integer getNum() {
        return num;
    }
}

class RealSubMenuItemOrderNumber implements SubMenuItemOrderNumber{
    private int num;
    @Override
    public Integer getNum() {
        return num;
    }
}

interface SubMenuItemOrderNumber{
    Integer getNum();
}

class MenuItemTypeId{}
class MenuIconId{}
class MenuIcon{}

interface MenuItem{
    MenuItemTypeId getTypeId();
    Map<SubMenuItemOrderNumber, SubMenuItem> getOrderNumToSubMenuItem();
}

interface SubMenuItem{
    SubMenuItemOrderNumber getOrderNum();
    List<MenuIcon> getIcons();
}

interface Publishable{
    void suspend();
    void publish();
}

interface ControllableMenuItem extends MenuItem, Publishable{
    void control(SubMenuItemOrderNumber orderNum, MenuIconId iconId, String iconData);
}

但问题是如果我想要MenuItemWithoutSubItems我必须MenuItemSubMenuItemTypeId Map我必须使用EnumSubMenuItemTypeId.ONLY_IF_MENU_ITEM_WITHOUT_SUB_ITEMS - &gt ;这是我的解决方法。类更简单,但它似乎仍然比需要更复杂。

我可以选择其他任何选项吗?

更新

这是第一个用例的潜在实现:

class DefaultMenuItemWithoutSubItems implements MenuItemWithoutSubItems {
    MenuItemTypeId id;
    List<MenuIcon> menuIcons;

    @Override
    public MenuItemTypeId getTypeId() {
        return id;
    }

    @Override
    public List<MenuIcon> getIcons() {
        return menuIcons;
    }
}

class DefaultMenuItemWithSubItems implements MenuItemWithSubItems {
    MenuItemTypeId id;
    Map<SubMenuItemOrderNumber, SubMenuItem> orderNumToSubMenuItem;

    @Override
    public MenuItemTypeId getTypeId() {
        return id;
    }

    @Override
    public Map<SubMenuItemOrderNumber, SubMenuItem> getOrderNumToSubMenuItem() {
        return orderNumToSubMenuItem;
    }
}

class DefaultSubMenuItem implements SubMenuItem {
    SubMenuItemOrderNumber orderNum;
    List<MenuIcon> menuIcons;

    @Override
    public SubMenuItemOrderNumber getOrderNum() {
        return orderNum;
    }

    @Override
    public List<MenuIcon> getIcons() {
        return menuIcons;
    }
}

class DefaultControllableMenuItemWithoutSubItems implements ControllableMenuItemWithoutSubItems {
    MenuItemTypeId id;
    List<MenuIcon> menuIcons;
    boolean suspended;

    @Override
    public MenuItemTypeId getTypeId() {
        return id;
    }

    @Override
    public List<MenuIcon> getIcons() {
        return menuIcons;
    }

    @Override
    public void suspend() {
        suspended = true;
    }

    @Override
    public void publish() {
        suspended = false;
    }

    @Override
    public void control(MenuIconId iconId, String iconData) {
        menuIcons.getById(iconId).replace(new MenuIcon(iconData));
    }
}

1 个答案:

答案 0 :(得分:0)

这看起来像是在使用复合模式时失败了。 这是复合模式背后的想法:

您有一个要公开的界面。例如:

public interface MenuItem {
    MenuItemTypeID getType();
    List<MenuIcon> getIcons();
}

接下来,你有一个基本的实现:

class SingleMenuItem implements MenuItem {
    private MenuItemTypeID id;
    private List<MenuIcon> icons;

    public SingleMenuItem(MenuItemTypeID id, List<MenuIcon> icons) {
        this.id = id;
        this.icons = icons;
    }

    @Override
    public MenuItemTypeID getType() {
        return id;
    }

    @Override
    public List<MenuIcon> getIcons() {
        return icons;
    }
}

这就是魔术。我们还希望有一个分组实现,但复合模式规定它的行为应该与普通的MenuItem完全相同。所以课程看起来像这样:

class MenuItemGroup implements MenuItem {
    private MenuItemTypeID id;
    private List<MenuItem> subMenuItems;

    public MenuItemGroup(MenuItemTypeID id, List<MenuItem> subMenuItems) {
        this.id = id;
        this.subMenuItems = subMenuItems;
    }

    @Override
    public MenuItemTypeID getType() {
        return id;
    }

    @Override
    public List<MenuIcon> getIcons() {
        List<MenuIcon> result = new ArrayList<>();
        for (MenuItem subItem : subMenuItems) {
            result.addAll(subItem.getIcons());
        }
        return result;
    }
}

现在,如果我们有一些MenuItem item,我们可以获得该菜单项中的所有图标。我们不在乎它是SingleMenuItem,还是MenuItemGroup,因为两者都会返回它们包含的所有图标。

请注意,我们还可以拥有一个包含更多组的组,这些组都包含一些SingleMenuItems,或者包含更多MenuItems组的SingleMenuItems组合。我们仍然像任何其他MenuItem一样使用它。

这在你的背景下是多么有用我不知道......