面向对象设计原则:抽象化

3
在阅读抽象时,我看到了以下语句:“抽象只捕获与当前视角相关的对象细节”。
例如: 从驾驶员的角度来看,Car类将是...
  public class Car
  {
     void start();
     void applybrakes();
     void changegear();
     void stop();
   }

从机械师的角度来看,车辆类将会是:

  public class Car
  {
     void changeOil();
     void adjustBrakes();
   }

我的问题是,在设计系统时,我们是为一个用户角度(司机或技工)设计,还是可以为多个用户角度设计,并根据用户类型进一步抽象出来?

希望我的问题很清楚。

谢谢

2个回答

7
根据您的使用情况,您可能需要为多个用户进行设计。例如,在您的示例中,如果您的汽车将由技工和驾驶员共同使用,则不能忽略其中一组用户。在这种情况下,您仍然可以使用接口抽象细节。
您可以像这样设计您的对象:
interface IDrivable {
    void start();
    void applyBrakes();
    void changeGear();
    void stop();
}

interface IFixable {
    void changeOil();
    void adjustBrakes();
}

public class Car : IDrivable, IFixable {
    // implement all the methods here
}

现在,当技工需要汽车时,你不会给他一个Car对象,而是给他一个IFixable对象。同样地,驾驶员得到一个IDrivable对象。这将同时保持两组用户的相关抽象。
class Driver {

    private IDrivable car;

    public Driver(IDrivable car) {
        this.car = car;
    }

    public driveCar() {
        this.car.start();
        this.car.accelerate();

        //this is invalid because a driver should not be able to do this
        this.car.changeOil();
    }
}

同样地,机械师将无法访问接口 IDrivable 中的方法。
您可以在此处阅读有关 interfaces 的更多信息。尽管这是 MSDN 链接并使用 C#,但所有主要语言都支持接口。

抢先一步了。很好的起点。 - Tony Hopkinson
但是当我这样做时:var driver = new Driver(new Car()),changeoil和adjustBrakes将被调用,因为Car类实现了两个接口(IDrivable、IFixable)。实际上,我在这里感到困惑,不知道在调用机械师的构造函数时应该传递什么依赖项? - ILoveStackoverflow
@ILoveStackoverflow 因为你正在创建一个'Car'对象,但司机获得的是一个'IDrivable'对象,所以即使你定义了'changeOil()'和'adjustBrakes()'方法,司机也无法调用它们。司机只能调用在'IDrivable'接口中定义的方法。 - Ayush
@xbonez 对不起,我明白了。我按照您的设计提出了问题,但有些困惑,如果您有时间,请查看:https://stackoverflow.com/questions/56596666/confusion-regarding-having-inheritance-or-not-in-my-design - ILoveStackoverflow

1

我认为你从“角度”中推断出了太多东西。在这里,我不会将“角度”解释为一个人或用户,而更多地是指视点。在这里,观点的概念甚至可能不是一个好的比喻。我们真正讨论的是如何划分责任,以便使用小对象来组成大对象。

这个想法的全部意义在于解耦和模块化。您希望能够提取和替换对象,而不必改变它们周围的一切。因此,您希望对象是连贯的,它们的方法和变量是密切相关的。

在对象之间的界面-客户端关系方面,您可能可以从用户隐喻中获得一些收益。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接