关于示例封装的问题

问题描述 投票:1回答:2

问题:

下面提供的Class SmartPhone,违反了封装规则。重新编写它以便保留封装。

class Battery{
    private String type;
    private int voltage;
    public Battery(String t, int v){type = t; voltage = v}
    public String getType(){return type;}
    public int getVoltage(){return voltage;} 
    public void setType(String t){type = t;}
    public void setVoltage(int v){voltage = v;}
}

class SmartPhone {
    private Battery battery;
    private String make, model;
    public SmartPhone(String make, String model, Battery battery){
        this.make = make; this.model = model;
        this.battery = battery;
    }
    public String getMake(){return make;} 
    public String getModel(){return model;}

    //I think here it is breaking encapsulation
    public Battery getBattery(){return battery;}
}

我看不到任何其他破坏封装的规则,我无法忘记为什么这破坏了封装。

是因为在此示例中,我们正在从该类外部返回另一个类的实例,所以它的battery从而破坏了封装?

java encapsulation
2个回答
-1
投票

封装意味着隐藏内部表示。需要删除任何揭示实现的方法(尤其是getBattery())。我将从删除所有吸气剂开始。

class SmartPhone {
    private final Battery battery;
    private final String make, model;

    public SmartPhone(String make, String model, Battery battery){
        this.make = make; this.model = model;
        this.battery = battery;
    }
}

这封装了电话实现的所有细节。

然后您应该添加电话应显示的表示behaviors的任何方法,例如打开/关闭的功能。

[在我看来,吸气剂破坏了封装,但是有时候没关系(例如getMake()getModel()方法对内部的了解不多)。您可以提供一种显示电压的方法,而不显示Battery对象本身的详细信息。 Law of Demeter之后。

class SmartPhone {
    private final Battery battery;
    private final String make, model;

    public SmartPhone(String make, String model, Battery battery){
        this.make = make; this.model = model;
        this.battery = battery;
    }

    public String getMake(){
        return make;
    } 

    public String getModel(){
        return model;
    }

    public void turnOn() {
        // TODO
    }

    public void turnOff() {
        // TODO
    }

    public int getVoltage() {
        return battery.getVoltage();
    }
}

-1
投票

[对于“封装规则”的含义没有更清晰的定义,这个问题有点模棱两可。但是我认为规则可能是这样的:

一个对象应该负责维护自己的状态,包括作为其组成部分的任何其他对象的状态。其他代码应该不可能直接更改对象的状态,而不使用对象在其公共接口中可用的mutator方法。

根据这样的规则,SmartPhone类违反了封装,因为它允许访问其内部具有设置方法的battery组件。如果我们认为电池的状态是电话内部状态的一部分(因为电池是电话的组成部分),则电池的设置方法允许对该内部状态进行突变,而不是通过电话的mutator方法。 >

有多个潜在的解决方案:我的首选是使Battery类不可变:

class Battery {
    private final String type;
    private final int voltage;
    public Battery(String t, int v) { type = t; voltage = v; }
    public String getType() { return type; }
    public int getVoltage() { return voltage; } 
}

通过这种方式,getBattery方法可以自由地返回对内部battery组件的引用,可以避免被其他代码所突变,因为电池没有任何mutator方法。

但是,这种问题暗示SmartPhone类是您应该更改的类,而不是Battery类。也许出于某些其他原因,要求电池具有设置方法。在这种情况下,问题会更加微妙。按照您当前编写类的方式,不仅可以通过battery方法来引用内部getBattery对象,还可以使用在构造对象时首先提供电池的人:

> Battery b = new Battery("Lithium ion", 5);
> SmartPhone s = new SmartPhone("Banana", "bPhone 2", b);
> s.getBattery().getVoltage()
5 (int)
> b.setVoltage(240); // danger! high voltage!
> s.getBattery().getVoltage()
240 (int)

请注意,由于我们保留了所提供电池的参考s,因此我们完全不需要通过b就可以对电池进行突变。

有两种解决方法,两种方法都不能像使电池不可变那样整洁。第一种方法是完全隐藏Battery类的内部细节,并使SmartPhone类本身具有所有四个属性:

class SmartPhone {
    private final Battery battery;
    private final String make, model;

    public SmartPhone(String make, String model, String bType, int bVoltage) {
        this.make = make;
        this.model = model;
        this.battery = new Battery(bType, bVoltage);
    }

    public String getMake() { return make; } 
    public String getModel() { return model; }

    public String getBatteryType() { return battery.getType(); }
    public int getBatteryVoltage() { return battery.getVoltage(); }
}

请注意,由于该类无法提供更改其值的方法,因此我将字段设为final

这绝对不允许外部访问电池的mutator方法。另外,我们可以制作防御性副本,以确保我们的私有引用永远不会对其他代码可用:

class SmartPhone {
    private final Battery battery;
    private final String make, model;

    public SmartPhone(String make, String model, Battery battery) {
        this.make = make;
        this.model = model;
        // defensive copy
        this.battery = new Battery(battery.getType(), battery.getVoltage());
    }

    public String getMake() { return make; } 
    public String getModel() { return model; }

    public Battery getBattery() {
        // defensive copy
        return new Battery(battery.getType(), battery.getVoltage());
    }
}

我不喜欢这种解决方案,因为它误导了它[[外观

电池的增变方法会做一些有用的事情,但是这些没有广告效果:> Battery b = new Battery("Lithium ion", 5); > SmartPhone s = new SmartPhone("Banana", "bPhone 2", b); > b.setVoltage(240); > s.getBattery().getVoltage() 5 (int) > s.getBattery().setVoltage(240); > s.getBattery().getVoltage() 5 (int)
© www.soinside.com 2019 - 2024. All rights reserved.