有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java使用OOPS扩展已编写的类

我正在努力学习设计实践和OOP。我用停车场问题作为例子开始

我有一个GeneralParkingLot接口和一个Vehicle接口。 GeneralParkingLot只有一个函数returnParkingLotSizeVehicle接口有多个车辆属性

我创建了一个类DowntownParkingLot,它扩展了GeneralParkingLot,并具有其他属性,如listOfCarsavailableSlots等,还有一个Car类,它扩展了Vehicle

我有一个HandlerClass来处理传入的命令,在这个类中,我有一个DownTownParkingLot对象和多个函数来处理命令,所以在每个函数中,我只需传递DowntownParkingLot的对象并对其进行操作

我创建了不同的服务,如CreateParkingLotObjectParkACarFreeASlot等,这些服务由命令处理程序调用

我还创建了单元测试来测试我的应用程序

我的问题是,如果我想扩展我当前的停车场,使其具有附加功能,比如说多楼层属性,或者如果我现在想处理多个停车场而不是一个停车场,那么扩展GeneralParkingLot类或DowntownParkingLot类的最佳方式是什么。我也读过关于适配器和装饰器模式的书,但我认为当我从一开始就遵循一个特定的设计模式时,这些模式很有用,在我的情况下,我没有遵循任何特定的模式,那么扩展代码的最佳方式是什么呢。我这样问是因为有时我们会遇到一个类,它不是根据任何设计模式生成的,并且被用于多个地方(比如很多API等),那么扩展这样一个代码的最佳方式是什么呢。从一开始重构是唯一的选择吗?或者创建从旧类继承的新类?最好的办法是什么?此外,我希望尽可能多地使用已经创建的单元测试,而不是再次重写相同的测试用例


共 (3) 个答案

  1. # 1 楼答案

    首先,让我们研究一下这里的一些术语,这样以后就不会让人困惑了。这里我假设上下文是Java,因为它被标记为Java

    1. 不要混合使用“类”和“接口”。类定义对象,接口定义行为。类不能扩展接口,只能实现它。但是,您可以使用一个接口扩展另一个接口,添加更多行为

    2. 不要混合使用“属性”和“字段”。对于一个类,属性通常意味着私有访问,而字段则意味着通过getter/setter进行公共访问

    第二,让我们研究OOP概念。OOP是对现实世界的抽象。应用程序设计的好坏完全取决于您对该领域的了解程度

    现在让我们来看看你的例子。你的主要概念只有一个:停车场。然而,在不同的领域,它意味着不同的抽象

    在支付应用程序中,它关心两件事:空间&;时间。还有多少空地,它们在哪里?对于停车场内的每个单元,它停了多长时间,离开时会有多少变化

    在一个交通控制应用程序中,它有一个完全不同的视角:有多少流量可以流动,以及引导流量的最佳路线是什么

    看,不同的领域即使在非常简单的概念上也会产生不同的设计。如果你发现自己在设计上绊倒了。试着忘记类/接口或OOP,只需先了解你的域,这在大多数情况下都能解决问题

    现在让我们开始研究一些细节。(由于我对你的领域不确定,我将根据我的理解简单解释设计过程。你可以吸收想法并定制你的设计)

    因为它是一个接口,所以它定义了行为。停车场应该有哪些行为?好吧,底线是:它应该告诉availableParkingSpaces,它应该能够park一辆车,当它离开时charge。现在我们定义了3种行为:

    int getAvailableParkingSpaces();
    int park(Vehicle v);
    int charge(Vehicle v);
    

    DowntownParkingLot:这应该是您的对象,它具有属性并实现行为

    class DowntownParkingLot implements GeneralParkingLot{
       private int totalSpaces;
       private int[] parking_slots;
       private Map<Integer, Vehicle> parkedVehicle;  //<park_space_id, vehicle>
    
       //implements of interface methods
    }
    

    MultiFloorParkingLot:我不确定这个多层建筑会如何影响你的设计,因为它隐藏在你的课堂中。 你的多层停车场是否提供了行为方面的额外服务?如果是的话,它应该是一个扩展GeneralParkingLotas的接口

    interface MultiFloorParkingLot extends GeneralParkingLot{
       //provide extra behaviours here
    }
    

    如果不是,它应该是一个停车位存储方式不同的类,如下所示:

    class MultiFloorParkingLot implements GeneralParkingLot{
        private int[][] parking_slots;  // locate parking_id by floor + park_num
    
        //everything else should not changed much.
    }
    

    就我个人而言,我不认为多层和单层有什么不同。多层或单层是建筑结构的概念,只有当应用程序需要定位/引导车辆到达可用空间时,多层或单层才有用。无论是在“第4层,A列,#24”中,还是在“第1区,B列,#25”中,在概念上都没有区别,区别在于实现,应该封装在类本身中。但同样,这取决于你的领域

    Vehicle:由于这是停车场车辆的概念,我们不在乎它的品牌、性能或任何与车辆本身相关的东西

    interface Vehicle {
        String getLicense();
        void park(GeneralParkingLot p);
    }
    

    Car:对于汽车,它至少应该有一个车牌,用作ID

    class Car implements Vehicle{
        String licensePlate;
        //if your domain needs to track how long it parks
        long enterTimeStamp, exitTimeStamp; 
    
        @Override
        public void park(GeneralParkingLot p){
            //do something that car needs to do, then register car on parking-lot
            p.park(this);
        }
    }
    

    看到了吗?将汽车停放到停车场的过程就是将汽车登记到停车场的过程。他们两人可能都需要做些什么来完成这个过程。他们各自要做的事情不应该由课外来做开闭原则:你可以告诉我做什么,但不能告诉我怎么做这样可以灵活地更改不同停车场中不同车辆的细节

    HandlerService:我不确定这个处理程序服务将如何工作,但在OO概念中,行为应该由对象本身执行。让我们编码:

    class HandlerService {
        //let's use park a car as example. 
        //notice that your using interface instead of class.
        //programming on interface, not class
        public void parkACar(Vehicle v, GeneralParkingLot p){
           v.park(p);
        }
    }
    

    不管怎样,编程就是梅勒尔y是解决问题的工具。而OOP只是一种抽象的方式。一个好的、灵活的设计取决于你的领域知识,而不是编程技能。所以,好好对待你的商业分析,并与他们成为朋友。^-^

    希望能有所帮助

  2. # 2 楼答案

    继承对教科书是有好处的,但实际上它是非常有限的。您应该使用接口和许多不同的实现:

    interface ParkingLot {
        void park(Vehicle v); 
    }
    
    interface Vehicle {
         int size();
         boolean isDIsabled();
    }
    

    你只暴露在最高层次上运作绝对需要的东西。就像停车场停放车辆一样。车辆只能放入停车位大小或禁用停车位。这就是停车场知道把车停在哪里的方法

    然后,每个实现类都会做它需要做的事情,以使流程正常工作。我认为floors是内部实现细节,可能不需要在API上公开,但可以在内部使用

    还建议使用工厂根据地板、电梯、厕所等建造停车场。。。因此,你有一种方法可以根据配置而不是硬编码构建一个通用停车场

    你可以使用“命令”在停车场之间传递停车命令,直到第一个停车场为你的车找到一个可供选择的停车位。在这种情况下,你把所有停车场都锁起来,并在它们之间传递请求。它也可以在楼层之间内部使用,因为每一层都会试图找到从底层到屋顶的匹配

    你可以用与找到停车位相关的功能来“装饰”你的车。所以你又有了一辆普通车,车上增加了不同的功能。停车场的设计也一样

    当你通过停车场命令时,停车场将阅读装饰的特征,并决定是否有停车位

    类似的方式,比如网站的用户角色(auth)的安全性

  3. # 3 楼答案

    我认为你必须在这里使用Visitor模式。由Gang of Four指定的visitor模式的定义是

    表示要在对象结构的元素上执行的操作。Visitor允许您定义新操作,而无需更改其操作的元素的类

    假设保持ParkingLot层次结构不变,那么可以为必须添加的每个新操作定义新的访问者。这将对现有的类和单元测试产生最小的更改,或者没有更改