当前位置: 首页 > news >正文

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

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

电梯问题-抽取关键需求

 1.电梯首先肯定是要可以上下不间断运行
 2.可以达到顶层或底层之后向反方向继续运行
 3.人员可以按钮然后等待电梯停在本楼层并进入
 4.进入的人可以选择自己的目的层数
 5.电梯可以在目的层数停止等待一定时间后继续运行

问题需求关键环节流程图

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

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

 我们创建对象以及方法要使用最小可用原则,既不需要的就不要加进对象,直到确定需要这个对象或  者属性或者方法再添加,所以可以如下分析
 依据时序图,我们初步分为了对象人person与对象电梯elevator
 对象电梯可以被启动,然后不断运行,所以我们觉得他应该有一个start方法
 我们也许会觉得对象人是外部触发电梯start 方法的对象
 电梯应该方法是判断是否到顶部isTop(),是否到底部isBottom(),并且有一个方法是wait() 等待人进入并且选择目标层数selectFloor(int floor)
 那么我们的对象建模就结束了,领域建模图如下

 

对象建模思考

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

 我个人认为都可以,这里我是按照不需要设计的,我这里把电梯运行和电梯本身认为是两个实体,你 可以用轿厢品牌1 带动电梯,第二天也可以用轿厢2带动电梯,
也就是说电梯是被外部轿厢发动机带动运行的,而电梯本身只负责内部运行逻辑处理
换句话说我的运行创建线程并不是电梯内部维护的,而是适用方,可以用线程池,也可以直接new thread
 这样就把更大的自由度留给了电梯合作方:电机轿厢,也符合易扩展多方合作的共赢思维

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

 本程序我们真的需要人这个对象吗,
 实际上人在这里的作用无非就是提供电梯需要停止的层数
 而实际上这个程序的外部使用者是真正活着的实体人
 因此,我们在程序里定义人这个对象是多余的,所以我们可以将对象人person这个类去掉,换成层数floor

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

 

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

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

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

相关文章:

  • vulnhub EMPIRE: BREAKOUT靶机
  • 【Python】PyQt5 Designer工具配置
  • Camera-MTK OpenCamera时序以及耗时
  • SpringCloud链路追踪SkyWalking-第二章-部署搭建及高可用
  • springboot vue3 elementui plus点餐外卖系统源码
  • Node.js阶段学习(一)
  • 一、nacos安装与高可用部署
  • mysql实现删除某一列的重复数据(只留一行或全部删除)
  • 数学建模十大算法01-蒙特卡洛算法(Monte Carlo)
  • 智能家居相关企业达2万余家,湖南智能家居发展将进入快车道
  • java计算机毕业设计高校学生社团管理源码+数据库+系统+lw文档+mybatis+运行部署
  • Flutter: FutureBuilder 组件的使用
  • CAS(Compare and swap)比较并交换算法解析
  • 大学生如何搭建属于自己的微信查题公众号
  • 如何采用Python读取一个图像
  • $translatePartialLoader加载失败及解决方式
  • 【跃迁之路】【477天】刻意练习系列236(2018.05.28)
  • 【跃迁之路】【669天】程序员高效学习方法论探索系列(实验阶段426-2018.12.13)...
  • C++入门教程(10):for 语句
  • conda常用的命令
  • Facebook AccountKit 接入的坑点
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • JDK 6和JDK 7中的substring()方法
  • Joomla 2.x, 3.x useful code cheatsheet
  • JS 面试题总结
  • mysql外键的使用
  • PV统计优化设计
  • Python 基础起步 (十) 什么叫函数?
  • vue脚手架vue-cli
  • WinRAR存在严重的安全漏洞影响5亿用户
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 构造函数(constructor)与原型链(prototype)关系
  • 记一次用 NodeJs 实现模拟登录的思路
  • 技术胖1-4季视频复习— (看视频笔记)
  • 嵌入式文件系统
  • 如何选择开源的机器学习框架?
  • 设计模式走一遍---观察者模式
  • 数据仓库的几种建模方法
  • 好程序员web前端教程分享CSS不同元素margin的计算 ...
  • 正则表达式-基础知识Review
  • ​​快速排序(四)——挖坑法,前后指针法与非递归
  • ​io --- 处理流的核心工具​
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • #大学#套接字
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (3)llvm ir转换过程
  • (floyd+补集) poj 3275
  • (Java实习生)每日10道面试题打卡——JavaWeb篇
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (二)JAVA使用POI操作excel
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (附源码)计算机毕业设计SSM基于健身房管理系统
  • (九十四)函数和二维数组