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简单表示

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


相关文章
|
2天前
|
JavaScript 安全 Java
智慧产科一体化管理平台源码,基于Java,Vue,ElementUI技术开发,二开快捷
智慧产科一体化管理平台覆盖从备孕到产后42天的全流程管理,构建科室协同、医患沟通及智能设备互联平台。通过移动端扫码建卡、自助报道、智能采集数据等手段优化就诊流程,提升孕妇就诊体验,并实现高危孕产妇五色管理和孕妇学校三位一体化管理,全面提升妇幼健康宣教质量。
28 12
|
6天前
|
存储 Java
Java中判断一个对象是否是空内容
在 Java 中,不同类型的对象其“空内容”的定义和判断方式各异。对于基本数据类型的包装类,空指对象引用为 null;字符串的空包括 null、长度为 0 或仅含空白字符,可通过 length() 和 trim() 判断;集合类通过 isEmpty() 方法检查是否无元素;数组的空则指引用为 null 或长度为 0。
|
26天前
|
Java
Java快速入门之类、对象、方法
本文简要介绍了Java快速入门中的类、对象和方法。首先,解释了类和对象的概念,类是对象的抽象,对象是类的具体实例。接着,阐述了类的定义和组成,包括属性和行为,并展示了如何创建和使用对象。然后,讨论了成员变量与局部变量的区别,强调了封装的重要性,通过`private`关键字隐藏数据并提供`get/set`方法访问。最后,介绍了构造方法的定义和重载,以及标准类的制作规范,帮助初学者理解如何构建完整的Java类。
|
25天前
|
安全 Java
Object取值转java对象
通过本文的介绍,我们了解了几种将 `Object`类型转换为Java对象的方法,包括强制类型转换、使用 `instanceof`检查类型和泛型方法等。此外,还探讨了在集合、反射和序列化等常见场景中的应用。掌握这些方法和技巧,有助于编写更健壮和类型安全的Java代码。
38 17
|
25天前
|
前端开发 Java 程序员
菜鸟之路day02-04拼图小游戏开发一一JAVA基础综合项目
本项目基于黑马程序员教程,涵盖面向对象进阶、继承、多态等知识,历时约24小时完成。项目去除了登录和注册模块,专注于单机游戏体验。使用Git进行版本管理,代码托管于Gitee。项目包含窗体搭建、事件监听、图片加载与打乱、交互逻辑实现、菜单功能及美化界面等内容。通过此项目,巩固了Java基础并提升了实际开发能力。 仓库地址:[https://gitee.com/zhang-tenglan/puzzlegame.git](https://gitee.com/zhang-tenglan/puzzlegame.git)
42 6
|
Java 开发工具 git
Java开发初级6.24.3
5.在Git使用过程中,进行Git配置的操作命令是哪个() A. config B. config -g C. config -a D. git config 相关知识点: 在git中,经常使用git config 命令用来配置git的配置文件,git配置级别主要有:仓库级别 local 【优先级最高】、用户级别 global【优先级次之】、系统级别 system【优先级最低】 正确答案:D 10.RDBMS是什么? A. Rela Database Management Systems B. Relational Database Management Systems C. Relation
147 0
|
SQL 前端开发 JavaScript
Java开发初级6.24.2
3.Java网站src/main/java目录保存的是什么资源? A. Java源代码文件 B. 测试代码 C. JavaScript、CSS等文件 D. 图片资源 正确答案:A 4.什么是索引Index? A. SQL数据库里的表管理工具 B. SQL数据库里的查询工具 C. SQL数据库里的目录工具 D. SQL数据库用来加速数据查询的特殊的数据结构 正确答案:D
163 0
|
Java
Java开发初级6.24.1
1.下面关于泛型的描述中错误的一项是? A. “? extends 类”表示设置泛型上限 B. “? super 类”表示设置泛型下限 C. 利用“?”通配符可以接收全部的泛型类型实例,但却不可修改泛型属性内容 D. 如果类在定义时使用了泛型,则在实例化类对象时需要设置相应的泛型类型,否则程序将无法编译通过 相关知识点: https://edu.aliyun.com/course/35 正确答案:D 2.下列选项中属于SVN中控制鉴权用户访问版本库的权限默认权限的是() A. write B. read C. none D. null 相关知识点: auth-access:取值范围为"writ
252 0
|
Java 开发工具 git
Java开发初级6.23.3
5.在Git使用过程中,进行Git配置的操作命令是哪个() A. config B. config -g C. config -a D. git config 相关知识点: 在git中,经常使用git config 命令用来配置git的配置文件,git配置级别主要有:仓库级别 local 【优先级最高】、用户级别 global【优先级次之】、系统级别 system【优先级最低】 正确答案:D 10.RDBMS是什么? A. Rela Database Management Systems B. Relational Database Management Systems C. Relation
138 0
|
SQL 前端开发 JavaScript
Java开发初级6.23.2
3.Java网站src/main/java目录保存的是什么资源? A. Java源代码文件 B. 测试代码 C. JavaScript、CSS等文件 D. 图片资源 正确答案:A 4.什么是索引Index? A. SQL数据库里的表管理工具 B. SQL数据库里的查询工具 C. SQL数据库里的目录工具 D. SQL数据库用来加速数据查询的特殊的数据结构 正确答案:D
235 0