面向对象设计
如何应对
面向对象设计的问题非常重要,它能反映出面试者的代码质量。若是对此类问题支支吾吾,面试多半就凶多吉少了。
应付面试中的含糊不清
面向对象设计的问题经常是有意含糊的,以此测试你是否会做假设,或者考验你是否会进一步地询问,以明确需求。否则当面对模棱两可的约束时,你又如何设计一个类呢?抛出你的问题来消除这些含糊,然后再设计类来处理剩余的含糊之处。
假定要为一副扑克牌做设计,考虑下面的问题:
1. 这副牌是用来干嘛?请询问你的面官。先不妨让我们假定这副牌是通用的,可以用来玩各种不同的扑克牌游戏
2.核心对象是什么?— 其中的子类型又是什么? 比如,核心对象可能是:扑克牌,一副扑克牌,数字,花色,点值(PointValue:不知道是指什么)
3. 有遗漏的地方吗?想想看,你如何使用这副牌来实现各种不同类型的游戏?如有必要可以对类的设计做更改
4. 思考一个更深入些的问题:如何实践你的方法?如果有一个方法叫CardDeck:getCard(Suit s,Number n),实现时你又如何去获取想要的牌呢?
现实世界的面向对象设计
现实世界的面向对象设计与软件行业的面向对象设计很类似,假设有一个停车场,你要对此做面向对象的设计:
1.目标是什么?比如:查看停车点是否可用,查看在停车站内,每种车型的数量,查看有障碍的停车点,等等。
2.思考其中的核心对象是什么(车,停车点,停车场,计时器等---车有不同的类型,停车点也分好几种,比如有障碍的停车点)
3.有所遗漏吗?我们如何表示停车的时间和付费限制?也许我们可以添加一个Permission(许可)类,该类用于处理各种不同的付费系统。
许可类也可有多个子类,比如PaidPermission(付费停车)以及FreeParking(免费停车)。停车场会有一个GetPermission函数,可以按照时间
来返回当前的许可对象。
4.我们如何得知车辆是否在停车点?思考一下数据采取哪种表示形式,可以使得该方法最有效。
7.1 请设计一个数据结构,用于一副通用的扑克。为了实现特定的扑克牌游戏,你又如何设计它的子类?
答案:
如果要实现21点游戏,我们需要知道牌的点数。JQK都是十点,A是11点(大部分情况是是这样的,但这是Hand类的工作,而不是
下面类的职责)
7.2 假设有一个呼叫中心,其中有三类员工:新人,技术领导(TL),产品经理(PM)。可能会有多个员工,但只有一个TL或PM。每个打进来的电话都先分配给有空的新人,当该新人无法处理电话中的事务时,他将此会叫转给技术领导,如果技术领导没空或不能处理,则电话应该分配给产品经理。请设计类和数据结构来解决此问题,实现的方法为getCallHandler()。
这三种员工都有自己的职责所在,所以这些特定的功能都跟具体的职位相关。在对应的类中,我们应该保持这种特性。
但这三种员工也有一些共性,比如他们都有家庭地址,姓名,职称,年龄等。这些属性可放在一个单独的类中,并作为父类被继承。
最后,应该有一个CallHander类,它将呼叫转移到相应的员工。
注意:对于面向对象设计的问题,可能会有很多种设计对象的方式。你应该和你的面官讨论各种方法的利弊,设计时,应该尽量考虑代码的长期灵活性和可维护性。
7.3 请使用面向对象的方法,设计一个音乐播放机。
首先,让我们看看一套基本的系统有哪些部分
1.CD播放器
2.CD
3.Display()(歌曲的播放长度,剩余时间和播放列表)
接下来,我们进行更细的分解
1.播放列表的创建(包括添加,删除,打乱等子功能)
2.CD选择
3.音道选择
4.将歌曲放入队列
5.从播放列表中获取下一首
用户也可被引导做下面的事情:
1.添加
2.删除
3.创建和编辑信息
我们如何基于对象将这些功能分类呢(哪些数据和功能结合在一起)?
面向对象设计的思路是,将数据和其相关的操作功能打包在一个单独的实体类中。
7.4 请使用面向对象的方法,设计一个象棋游戏。
7.5 请设计在线读书系统的数据结构
问题中没有太多功能描述,所以我们假定需要实现一个基本的在线读书系统,它具有以下功能:
1.用户创建和延续
2.寻书
3.读书
为了实现这些功能,我们可能需要其他的函数,比如获取,设置和更新等。所需的对象包括User,Book和Library.
下面的代码和面向对象设计描述了这些功能:
对于此类系统,我们做的设计是一种简化实现。我们有一个User类,用于维护所有用户相关的信息,并有一个标识符保证用户的唯一性。我们可以添加一些功能,比如用户注册,收取用户费用和设置月日的看书限额,等等
接下来,我们创建了book类,其中维护了所有书的信息。可以加入诸如add/delete/update等函数。
最后,我们创建了一个管理类,用来管理在线读书系统,它有一个监听接口,以监听任何登录请求。它也提供了图书搜索功能和展示功能。由于用户和该类会发生交互,所以搜索必须在此类中实现。
7.6 实现一个拼图游戏,请设计用到的数据结构,并解释拼图算法
概述:
1.我们根据边的类型来将其分组。因为内边和外边相伴,反之亦然,这样我们可以直接去寻找潜在匹配。
当我们向内走时,我们记下拼图问题的内边周长(exposed_edges),该变量初始化为角落处的边。
7.7在提供了后台的各种部件,类和方法的细节后,你 如何设计一个聊天服务程序?最难解决的问题是什么?
我们的聊天服务器是什么?
这是你和面官需要讨论的问题,不过先让我们做几个假设:设想我们实现的是一个基本的聊天服务,只支持少数几个人。
用户拥有联系人列表,可以看到朋友在线与否,它们可以发送文本信息给好友。我们不必设计群聊,语音聊天等功能。另外,需要注意到联系人列表是双向的:互为好友才能联系。一切都简化了。
那么,这个系统需要支持哪些功能呢?
1.用户A上线
2.根据当前状态,用户A请求其联系人列表
3.A的好友看到A上线了
4.A添加B到联系人列表
5.A向B发送文本消息
6.A更改状态信息或状态类型
7.A移除B
8.A下线
从这些需求中我们了解了什么?
我们必须有用户,添加请求状态,在线状态和消息等概念。
核心组件是什么?
我们需要一个存储条目的数据库,以及一个总是在线的服务程序。在服务端和客户端,我们推荐使用XML作为传输格式,因为它对于人和机器都是易读的。
核心对象和方法是什么?
下面列出了核心对象和方法,注意到我们隐藏了很多细节,比如如何将数据实际推送给客户端。
最难解决的问题是什么(或者最有趣的问题)?
1.如何获取某人是否在线---意思是,真实的获取?
用户下线时,我们希望能知道其状态,但实际上情况并非如此。用户的连接可能会断。为了确保其下线,我们通常会尝试使用ping来连接客户端。
2.如何处理不一致的信息?
内存和数据库中的信息有可能不一致,发生信息同步问题时会有什么表现?到底以那个数据为准?
3.如何使服务器可升级?
虽然我们设计的系统没有太考虑可升级性,但在实际开发中,这是一个重要的问题。我们需要将数据分布到多台服务器,如此,数据不同步的问题又会凸显出来。
4.如何防止服务器被攻击?
客户端会向我们推送数据-----如果它们向我们发动DOS系统怎么办?如何防止呢?
7.8 奥赛罗的玩法如下:每个奥赛罗一面是白色,一面是黑色。当某个奥赛罗的左右或上下被其反色的奥赛罗包围时,称它被捕获了,它需要翻过来。
在轮到你玩时,你必须捕获至少一个你对手的奥赛罗。当玩家都不能再下子时,游戏结束,赢家为拥有奥赛罗最多的一方。请使用面向对象设计来
实现奥赛罗游戏。
奥赛罗有如下主要步骤:
1. Game()为主函数,来管理游戏中的所有活动
2.构造函数对游戏进行初始化
3.获取第一个玩家的输入
4.验证输入
5.更改棋盘格局
6.检验是否有人获胜了
7.获取第二个玩家的输入
7.9 请为一个内存文件系统设计数据结构和算法,尽量结合代码讲解。
对与数据块的分配,我们可以使用位掩码数组和线性查找(参见“实际文件系统设计”)或B+树(参见维基百科)
7.10 使用C++,实现一个垃圾回收器,并描述用到的数据结构和算法。
在C++中,使用引用技术实现垃圾回收的,基本上总是以智能指针的形式出现,它执行的就是引用计数。使用智能指针而非一般指针的原因是,
概念上的实现简洁和易于使用。
使用智能指针后,所有的垃圾回收都在后台完成---通常是在构造函数,析构函数,赋值运算符,显式对象管理函数等中出现。
有两类函数,每类都有简单:
C++的引用计数有几种实现:
1.简单引用计数
优势:性能
缺点:内存开销大,因为使用了两个指针
2.二选一的引用计数
优势:没有因为两个指针造成的内存开销
缺点:由于外加了一层,性能会有损耗
3.侵入式引用计数
优势:没有上一个的劣势
缺点:使用侵入式引用计数的类需要修改
3.所有权列表引用计数。这种方法可取代第1到第3种方法。前三种方法中,只有检验计数是否为0才是重要的---实际上具体为多少并不重要。方案4的主要思想正在于此。
给定对象的所有智能指针都存放在双链表中。智能指针的构造函数将节点添到链表,而析构函数负责从链表中移除节点,并检验链表是否为空。如果为空,则删除对象。
From:http://article.yeeyan.org/view/49656/195817