java面向对象思维程序设计开发以及案例 -电梯运行问题对象分析与程序设计(1)

简介: java面向对象思维程序设计开发以及案例 -电梯运行问题对象分析与程序设计(1)

电梯是我们日常生活中经常看见和使用的运载工具,但其中也隐藏着一个精而小的程序,我们今天模拟一个电梯运行程序来开始我们面向对象之旅


电梯问题-抽取关键需求


1.电梯首先肯定是要可以上下不间断运行

2.可以达到顶层或底层之后向反方向继续运行

3.人员可以按钮然后等待电梯停在本楼层并进入

4.进入的人可以选择自己的目的层数

5.电梯可以在目的层数停止等待一定时间后继续运行


问题需求关键环节流程图


我们进入需求转化环境,我们来梳理一下需求并且转化为一个时序图,便于我们拆分对象以及确定逻辑顺序,流程图如下

1.png

初步领域对象分析,最小可用原则


我们创建对象以及方法要使用最小可用原则,既不需要的就不要加进对象,直到确定需要这个对象或  者属性或者方法再添加,所以可以如下分析

依据时序图,我们初步分为了对象人person与对象电梯elevator

对象电梯可以被启动,然后不断运行,所以我们觉得他应该有一个start方法

我们也许会觉得对象人是外部触发电梯start 方法的对象

电梯应该方法是判断是否到顶部isTop(),是否到底部isBottom(),并且有一个方法是wait() 等待人进入并且选择目标层数selectFloor(int floor)

那么我们的对象建模就结束了,领域建模图如下

1.png

对象建模思考


思考1:电梯运行是否内部维护运行状态,是否需要一个start方法


我个人认为都可以,这里我是按照不需要设计的,我这里把电梯运行和电梯本身认为是两个实体,你 可以用轿厢品牌1 带动电梯,第二天也可以用轿厢2带动电梯,

也就是说电梯是被外部轿厢发动机带动运行的,而电梯本身只负责内部运行逻辑处理

换句话说我的运行创建线程并不是电梯内部维护的,而是适用方,可以用线程池,也可以直接new thread

这样就把更大的自由度留给了电梯合作方:电机轿厢,也符合易扩展多方合作的共赢思维


思考2:是否需要人这个person对象


本程序我们真的需要人这个对象吗,

实际上人在这里的作用无非就是提供电梯需要停止的层数

而实际上这个程序的外部使用者是真正活着的实体人

因此,我们在程序里定义人这个对象是多余的,所以我们可以将对象人person这个类去掉,换成层数floor

重新分析后-最终领域对象图

1.png

面向对象程序设计核心思想原则


1.就是让人从外面看起来就知道你的代码是在干什么,每一个对象都要有意义,并且真实符合世界上实体事物运行规则

2.设计的对象没有绝对的对与错,只要让人觉得你的对象确实合理并且使用起来符合正常人的思维习惯就可以

经过以上分析建模,形成目前的初版代码如下

public class ElevatorTest {
    public static void main(String[] args){
        //18层的电梯
        int floor = 18;
        //电梯初始化
        Elevator elevator = new Elevator(floor);
        //创建一个线程池,初始化两个线程,1:电梯运行线程,2:模拟随机层数人员进入电梯线程
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,2,10L, TimeUnit.SECONDS,new  ArrayBlockingQueue(2));
        //启动电梯
        threadPoolExecutor.execute(elevator);
        //模拟随机楼层人员进电梯与出电梯
        threadPoolExecutor.execute(()->{
                while (true){
                    //模拟随机生成 1~18楼人
                    int enterRandom = new Random().nextInt(18);
                    if(enterRandom ==0){
                        continue;
                    }else {
                        try {
                            //人员进入
                            elevator.enter(enterRandom);
                            Thread.sleep(3000);
                        }catch (InterruptedException e){
                        }
                    }
                }
        });
    }
}
class Elevator implements Runnable {
    boolean start = false;
    int currentFloor ;
    boolean directionTop = true;
    int floor ;
    //保存目标层数map
    Map enterMap = new HashMap(18);
    ReentrantLock lock = new ReentrantLock();
    public Elevator(int floor){
        this.floor = floor;
        this.currentFloor = 1;
        System.out.println("初始化了一个"+floor+"层的电梯,当前电梯在第1层");
    }
    /**
     * 人员进入电梯同时选择好目标层数
     * */
    public void enter(int outFloor){
        lock.lock();
        System.out.println("人员进入,按了"+outFloor+"层");
        enterMap.put(outFloor,null);
        lock.unlock();
    }
    /**
     * 是否是顶层
     * */
    public boolean isTop(){
        return this.currentFloor == floor;
    }
    /**
     * 是否是底层
     * */
    public boolean isBottom(){
        return this.currentFloor == 1;
    }
    @Override
    public void run() {
        System.out.println("电梯启动");
        start = true;
        while (start){
            if(!lock.isLocked()) {
                try {
                    if (directionTop) {
                        currentFloor++;
                        System.out.println("当前在电梯第" + currentFloor + "层");
                        //该层人员出门出门后将该层移除
                        if(enterMap.containsKey(currentFloor)){
                            try {
                                System.out.println(currentFloor+"人员出门");
                                enterMap.remove(currentFloor);
                                System.out.println("剩余楼层"+enterMap.keySet());
                                Thread.sleep(5000);
                            }catch (Exception e){
                            }
                        }
                        if (isTop()) {
                            directionTop = false;
                            System.out.println("到达顶层,开始向下运行");
                        }
                    } else {
                        currentFloor--;
                        System.out.println("当前在电梯第" + currentFloor + "层");
                        //该层人员出门出门后将该层移除
                        if(enterMap.containsKey(currentFloor)){
                            try {
                                System.out.println(currentFloor+"人员出门");
                                enterMap.remove(currentFloor);
                                System.out.println("剩余楼层"+enterMap.keySet());
                                Thread.sleep(5000);
                            }catch (Exception e){
                            }
                        }
                        System.out.println("当前在电梯第" + currentFloor + "层");
                        if (isBottom()) {
                            directionTop = true;
                            System.out.println("到达1层,开始向向运行");
                        }
                    }
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
            }else {
                try {
                    System.out.println("进人中。。");
                    Thread.sleep(5000);
                }catch (Exception e){
                }
            }
        }
    }
}

运行输出结果


初始化了一个18层的电梯,当前电梯在第1层

电梯启动

当前在电梯第2层

人员进入,按了17


当前在电梯第3层

当前在电梯第4层

当前在电梯第5层

人员进入,按了13


当前在电梯第6层

当前在电梯第7层

当前在电梯第8层

人员进入,按了7


当前在电梯第9层

当前在电梯第10层

当前在电梯第11层

人员进入,按了6


当前在电梯第12层

当前在电梯第13层

13人员出门

剩余楼层[6, 7, 17]

人员进入,按了11


人员进入,按了4


当前在电梯第14层

人员进入,按了13


当前在电梯第15层

当前在电梯第16层

当前在电梯第17层

17人员出门

剩余楼层[4, 6, 7, 11, 13]

人员进入,按了7


人员进入,按了1


当前在电梯第18层

到达顶层,开始向下运行

人员进入,按了16


当前在电梯第17层

当前在电梯第17层

当前在电梯第16层

16人员出门

剩余楼层[1, 4, 6, 7, 11, 13]

人员进入,按了4


人员进入,按了3


当前在电梯第16层

当前在电梯第15层

当前在电梯第15层

当前在电梯第14层

当前在电梯第14层

人员进入,按了14


当前在电梯第13层

13人员出门

剩余楼层[1, 3, 4, 6, 7, 11, 14]

人员进入,按了10


当前在电梯第13层

人员进入,按了10


当前在电梯第12层

当前在电梯第12层

当前在电梯第11层

11人员出门

剩余楼层[1, 3, 4, 6, 7, 10, 14]


面向对象到底是节省时间还是浪费时间


其实使用面向对象角度建模并且进行程序开发并不是耗费时间,而是节省时间

因为设计的对象是充血模型,所以后续其他业务使用对应功能只需要对象.方法就可以了,这也是DDD 领域驱动设计的核心思想

而且面向对象设计开发也是利于大家对需求转化的加深,会加速开发效率,比如这个程序我建模可能用了30分钟,但编码只用了15分钟左右


结语


程序是依照我们小设计原则没有任何优化重构编写的,肯定细节上还有容错以及重用上有很多问题

但这就是程序设计,因为他满足了最小化的我们的需求

但是,问题终究是问题,我们还是要解决的,先把当前代码重构,然后我们要把缺失逻辑补充:

比如并没有实现人按电梯上下进入的操作,进入的人并没有实现同时允许多层数选择的操作等

没有使用层数floor对象,而是用map简单表示

下一篇我们将继续优化并完成这个电梯程序


目录
打赏
0
0
0
0
18
分享
相关文章
java面试-基础语法与面向对象
本文介绍了 Java 编程中的几个核心概念。首先,详细区分了方法重载与重写的定义、发生阶段及规则;其次,分析了 `==` 与 `equals` 的区别,强调了基本类型和引用类型的比较方式;接着,对比了 `String`、`StringBuilder` 和 `StringBuffer` 的特性,包括线程安全性和性能差异;最后,讲解了 Java 异常机制,包括自定义异常的实现以及常见非检查异常的类型。这些内容对理解 Java 面向对象编程和实际开发问题解决具有重要意义。
43 15
重学Java基础篇—Java对象创建的7种核心方式详解
本文全面解析了Java中对象的创建方式,涵盖基础到高级技术。包括`new关键字`直接实例化、反射机制动态创建、克隆与反序列化复用对象,以及工厂方法和建造者模式等设计模式的应用。同时探讨了Spring IOC容器等框架级创建方式,并对比各类方法的适用场景与优缺点。此外,还深入分析了动态代理、Unsafe类等扩展知识及注意事项。最后总结最佳实践,建议根据业务需求选择合适方式,在灵活性与性能间取得平衡。
56 3
Java对象创建和访问
Java对象创建过程包括类加载检查、内存分配(指针碰撞或空闲列表)、内存初始化、对象头设置及初始化方法执行。访问方式有句柄和直接指针两种,前者稳定但需额外定位,后者速度快。对象创建涉及并发安全、垃圾回收等机制。
Java对象创建和访问
Java中判断一个对象是否是空内容
在 Java 中,不同类型的对象其“空内容”的定义和判断方式各异。对于基本数据类型的包装类,空指对象引用为 null;字符串的空包括 null、长度为 0 或仅含空白字符,可通过 length() 和 trim() 判断;集合类通过 isEmpty() 方法检查是否无元素;数组的空则指引用为 null 或长度为 0。
中南林业科技大学Java实验报告一:第一个可以运行的JAVA程序
中南林业科技大学Java实验报告一:第一个可以运行的JAVA程序
212 0
Java - 传带命令参数运行程序
Java - 传带命令参数运行程序
622 0
Java - 传带命令参数运行程序
JAVA万能:JNLP在浏览器上以WEB方式运行JAVA程序
JAVA万能:JNLP在浏览器上以WEB方式运行JAVA程序
556 0
《Java编码指南:编写安全可靠程序的75条建议(英文版)》—— 2.8 运行Java程序
要查看Saluton程序的结果是否如你所愿,可使用Java虚拟机(JVM)运行类文件,JVM就是运行所有Java代码的解释器。在NetBeans中,选择菜单命令Run->Run File。在源代码编辑器的下面将会打开输出面板。如果没有错误,则该程序会在该面板中显示输出结果,如图2.3所示。
1578 0