设计类的层次结构

时间:2018-03-12 15:31:47

标签: java oop design-patterns

我在班级设计中有这种层次结构:

enter image description here

我想要实现的是最通用的类​​设计,它将足够灵活地覆盖所有情况。

正如您在图片中看到的那样,我们有一些具有某种材料的笼子。现在,根据材料类型,我们可以根据颜色对笼子进行进一步分类(因此,如果是塑料笼子,我们将有2个隔间,其中一个是红色,另一个是蓝色),可以容纳动物。

如果是更具体的笼子(例如PLASTIC),我应该可以打电话给getBrightestColor(),这对于METAL笼子来说是不存在的。 WOOD-en笼的情况就是更复杂的塑料笼。

这是我到目前为止的一些代码,但我认为两者都不行(在代码注释中添加了可能的问题):

Cage cg = new Cage(new Specifier(Material.METAL));
cg.addAnimal(new Elephant());
cg.addAnimal(new Dog());
cg.addAnimal(new Cat());
cg.emptyCage();

CageWithSpecifier cg2 = new CageWithSpecifier(new Specifier(Material.PLASTIC)); //need to have different class than Cage, and they are more less same??
cg2.addAnimal(new Specifier(Color.RED), new Dog());
cg2.addAnimal(new Specifier(Color.RED), new Elephant());
cg2.addAnimal(new Specifier(Color.BLUE), new Elephant());
cg2.addAnimal(new Specifier(Color.BLUE), new Cat());
String bc1 = cg2.getBrightestColor();
cg2.emptyCage();

CageWithSpecifier cg3 = new CageWithSpecifier(new Specifier(Material.WOOD));
cg3.addAnimal(new Specifier(Wood.OAK, Color.RED), new Dog());
cg3.addAnimal(new Specifier(Wood.OAK, Color.BLACK), new Elephant());
cg3.addAnimal(new Specifier(Wood.MAPLE, Color.RED), new Dog());

//cg3.getBySpecifier --> ideally should know if it returns leaf or node in hierarchy (without casting?); here we need to cast and whatnot
String bc2 = cg3.getBySpecifier(new Specifier(Wood.OAK)).getBrightestColor();

这个使用复合材料:

//using Composite pattern ?
Cage cg3 = new Cage(new Specifier(Material.WOOD));
Cage cg3s1 = new Cage(new Specifier(Wood.OAK)); //cg3s1 is not leaf, but has addAnimal()
Cage cg3s1s1 = new Cage(new Specifier(Color.RED));  //cg3s1s1 is leaf, but will have also addCage()
cg3s1s1.addAnimal(new Dog());
cg3s1.addCage(cg3s1s1);
cg3.addCage(cg3s1);

我猜应该是某种复合模式?有人有更好的建议吗?

更新功能要求

我需要能够在笼子里面添加动物(例如METAL)或在笼子里面添加说明符(例如PLASTIC+RED)。如果我有多个彩色内笼(例如PLASTIC笼子或WOOD+OAK),我需要能够getBrightestColor()。 Cage需要使用empty()方法清除笼中的所有动物,或empty(Specifier)将所有动物从内笼中清空(如果我在empty()上调用PLASTIC笼子里,所有动物都将从REDBLUE中清空。将来可能会有更多级别的说明符(例如GLASS_COLORED__BRIGHT ____ RED)。

2 个答案:

答案 0 :(得分:0)

在此实现中,如果将错误的动物放入错误的隔间,则会生成编译器错误。

如果API被滥用,应始终努力生成编译器错误。这可以最大限度地减少运行时错误和错误。

Visitor pattern可用于在只有类型超类的引用可见的情况下对超类的子类执行特定于子类的操作。

用法:

xhr.open("GET", "https://www.myapi.com/api/v1/objects/1.json", false);

笼:

MetalCage metalCage = new MetalCage();
metalCage.getRegularMetalCompartment().add(new Dog());
metalCage.getRegularMetalCompartment().empty();

PlasticCage plasticCage = new PlasticCage();
plasticCage.getBluePlasticCompartment().add(new Elephant());
plasticCage.getRedPlasticCompartment().add(new Dog());
plasticCage.getRedPlasticCompartment().empty();

WoodCage woodCage = new WoodCage();
woodCage.getRedOakWoodCompartment().add(new Dog());
woodCage.getBlackOakWoodCompartment().add(new Elephant());
woodCage.getRedMapleWoodCompartment().add(new Dog());
woodCage.getRedMapleWoodCompartment().empty();

隔室:

abstract class Cage {
    abstract public Color getBrightestColor();
}

class MetalCage extends Cage {

    private final MetalCompartment regularMetalCompartment = new MetalCompartment();

    public MetalCompartment getRegularMetalCompartment() {
        return regularMetalCompartment;
    }

    @Override
    public Color getBrightestColor() {
        return Color.BLACK;
    }
}

class PlasticCage extends Cage {

    private final RedPlasticCompartment redPlasticCompartment = new RedPlasticCompartment();
    private final BluePlasticCompartment bluePlasticCompartment = new BluePlasticCompartment();

    public BluePlasticCompartment getBluePlasticCompartment() {
        return bluePlasticCompartment;
    }

    public RedPlasticCompartment getRedPlasticCompartment() {
        return redPlasticCompartment;
    }

    @Override
    public Color getBrightestColor() {
        return Color.RED;
    }
}

class WoodCage extends Cage {

    private final RedOakWoodCompartment redOakWoodCompartment = new RedOakWoodCompartment();
    private final BlackOakWoodCompartment blackOakWoodCompartment = new BlackOakWoodCompartment();
    private final RedMapleWoodCompartment redMapleWoodCompartment = new RedMapleWoodCompartment();

    public RedOakWoodCompartment getRedOakWoodCompartment() {
        return redOakWoodCompartment;
    }

    public BlackOakWoodCompartment getBlackOakWoodCompartment() {
        return blackOakWoodCompartment;
    }

    public RedMapleWoodCompartment getRedMapleWoodCompartment() {
        return redMapleWoodCompartment;
    }

    @Override
    public Color getBrightestColor() {
        return Color.RED;
    }
}

动物

abstract class Compartment<Prisoner> {
    private final List<Prisoner> prisoners = new ArrayList<Prisoner>();

    public List<Prisoner> getPrisoners() {
        return prisoners;
    }

    public void add(Prisoner prisoner) {
        prisoners.add(prisoner);
    }

    public void empty() {
        prisoners.clear();
    }
}

class MetalCompartment extends Compartment<MetalCompartment.Prisoner> {
    interface Prisoner {
    }
}

class RedPlasticCompartment extends Compartment<RedPlasticCompartment.Prisoner> {
    interface Prisoner {
    }
}

class BluePlasticCompartment extends Compartment<BluePlasticCompartment.Prisoner> {
    interface Prisoner {
    }
}

class RedOakWoodCompartment extends Compartment<RedOakWoodCompartment.Prisoner> {
    interface Prisoner {
    }
}

class BlackOakWoodCompartment extends Compartment<BlackOakWoodCompartment.Prisoner> {
    interface Prisoner {
    }
}

class RedMapleWoodCompartment extends Compartment<RedMapleWoodCompartment.Prisoner> {
    interface Prisoner {
    }
}

答案 1 :(得分:0)

你可以在这里使用复合。虽然我没有展示它的实现,但我想到了这样的东西,可能会给你一些关于如何解决这个问题的想法。大脑食物

使用的枚举:

enum Property {
OAK, MAPLE
}

enum Color {
BLUE, RED, BLACK
}

enum Material {
METAL, PLASTIC, WOOD
}

Cage,Compartment和示范动物类

class Cage {
Material material;
HashSet<Compartment> compartments;
HashMap<Property, HashSet> compartmentsByProperty;

Cage(Material material) throws NoSuchMaterialException {
    switch (material) {
        case METAL: // for no Properties and single compartment
            compartments = new HashSet<>();
            compartments.add(new Compartment());
            break;
        case PLASTIC: // for no Properties and multiple compartments
            compartments = new HashSet<>();
            compartments.add(new Compartment(Color.BLUE));
            compartments.add(new Compartment(Color.RED));
            break;
        case WOOD: // for multiple Properties and multiple compartments for each
            compartmentsByProperty = new HashMap<>();
            HashSet<Compartment> oakCompartments = new HashSet<>();
            oakCompartments.add(new Compartment(Color.BLACK));
            oakCompartments.add(new Compartment(Color.RED));
            compartmentsByProperty.put(Property.OAK, oakCompartments);
            HashSet<Compartment> mapleCompartments = new HashSet<>();
            oakCompartments.add(new Compartment(Color.RED));
            compartmentsByProperty.put(Property.MAPLE, mapleCompartments);
            break;
        default:
            throw new NoSuchMaterialException();
    }
}

void empty() {
    // clear stuff
}
}

class Compartment {
private Color color;
private ArrayList compartment;

Compartment() {
    compartment = new ArrayList<Animal>();
}

Compartment(Color color) {
    this.color = color;
    compartment = new ArrayList<Animal>();
}

public void clear() {
    compartment.clear();
}
}

class Elephant extends Animal {}

虽然有一条评论,但请尽量让OOP简单易懂,因为它应该如何完成。它与您如何命名变量,类和方法有关!如果您认为必须为cg3s1s1CageWithSpecifier类型的变量命名,那么这个想法很可能首先出现问题。