重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
可以把组合体想象成为一个实体,它包含着同一类型的其它实体。例如算术表达式,其包括操作数、操作符和另一个操作数,其中,另一个操作数也可以是操作数、操作符和另一个操作数。整个结构就像由父节点实体和子节点实体连接而成的树。它就像同一个祖先的族谱树一样,族谱中每个节点都有相同的姓。假设询问曾祖父(树的根节点),请问家里几口人?操作将从树根往下传,树中的每个有孩子的组合体会对孩子的总数与孩子们返回的数求和,然后将这个和返回。不必分别请求族谱树中的每个成员,可以向树发送消息对其整体进行操作。
创新互联是一家以网络技术公司,为中小企业提供网站维护、成都网站建设、成都网站设计、网站备案、服务器租用、域名注册、软件开发、小程序定制开发等企业互联网相关业务,是一家有着丰富的互联网运营推广经验的科技公司,有着多年的网站建站经验,致力于帮助中小企业在互联网让打出自已的品牌和口碑,让企业在互联网上打开一个面向全国乃至全球的业务窗口:建站联系电话:18982081108
在面向对象软件设计中我们借用类似的思想,组合结构可以非常复杂,我们需要通过统一的接口把整个复杂结构作为一个整体来使用,所以客户端不必知道某个节点是什么就能够使用它。
组合模式,又叫部分整体模式,将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。什么是部分-整体的层次结构呢?它是既包含对象的组合又包含作为叶节点的单个对象的一种层次结构。每个组合体包含的其它节点,可以是叶节点或者是其它组合体,这种关系在这个层次结构中递归重复,因为每个组合或者叶节点具有相同的类型。下图是运行时组合对象结构的一个例子:
组合模式的静态结构下类图所示:
Component 定义了 Leaf 类和 Composite 类的共同操作,组合模式使得客户端可以统一处理 Leaf 和 Composite 对象。 Leaf 和 Composite 的主要区别在于 Leaf 节点不包含同类型的子节点,而 Composite 则包含。 Composite 通过 add:Component 和 remove:Component 管理子节点。
在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
在 Cocoa 中, UIView 被组织成一个组合结构,每个 UIView 的实例可以包含 UIView 的其它实例,形成统一的树形结构。让客户端对单个 UIView 对象和 UIView 的组合统一对待。
窗口中的 UIView 在内部形成视图的树形结构。层次结构的根部是一个窗口( UIWindow 对象)及其内容视图,一个填充窗口内容矩形的透明视图。添加到内容视图的视图成为它的子视图,并且它们成为添加到它们的任何视图的父视图。除了内容视图,一个视图有一个(并且只有一个)父视图 和零或任意数量的子视图。可以将此结构视为包含: 父视图包含其子视图 。
视图层次结构是一种结构体系结构,它在绘图和事件处理中都起作用。一个视图有两个边界矩形,它的框架和它的边界,这会影响视图的图形操作是如何发生的。框架是外部边界;它在其父视图的坐标系中定位视图,定义其大小,并将绘图剪辑到视图的边缘。bounds,内部边界矩形,定义了视图自身绘制的表面的内部坐标系。
当窗口系统要求窗口准备显示时,父视图被要求在其子视图之前呈现自己。当向视图发送一些消息时——例如,请求视图重绘自身的消息——该消息被传播到子视图。因此,可以将视图层次结构的一个分支视为统一视图。
组合模式的主要意图是让树形结构中的每个节点具有相同的抽象接口。这样整个结构可以作为一个统一的抽象结构使用,而不暴露其内部表示。对每个节点的任何操作,可以通过协议或抽象基类中的相同接口来进行。在 Cocoa 中,UIView 视图被组合成一个组合结构,思考一个问题,使用树型结构使得对应视图的数据被组合成一个组合结构与其一一对应实现动态渲染...
代理模式是一种消息传递方式,一个完整的代理模式包括:委托对象、代理对象和协议。
协议:用来指定代理双方可以做什么,必须做什么。
委托对象:根据指定的协议,指定代理去完成什么功能。
代理对象:根据指定的协议,完成委托方需要实现的功能。
从上图中可以看到三方之间的关系,在实际应用中通过协议来规定代理双方的行为,协议中的内容一般都是方法列表,当然也可以定义属性。
协议是公共的定义,如果只是某个类使用,我们常做的就是写在某个类中。如果是多个类都是用同一个协议,建议创建一个Protocol文件,在这个文件中定义协议。遵循的协议可以被继承,例如我们常用的 UITableView ,由于继承自 UIScrollView 的缘故,所以也将 UIScrollViewDelegate 继承了过来,我们可以通过代理方法获取 UITableView 偏移量等状态参数。
协议只能定义公用的一套接口,类似于一个约束代理双方的作用。但不能提供具体的实现方法,实现方法需要代理对象去实现。协议可以继承其他协议,并且可以继承多个协议,在iOS中对象是不支持多继承的,而协议可以多继承。
协议有两个修饰符 @optional 和 @required ,创建一个协议如果没有声明,默认是 @required 状态的。这两个修饰符只是约定代理是否强制需要遵守协议,如果 @required 状态的方法代理没有遵守,会报一个黄色的警告,只是起一个约束的作用,没有其他功能。
无论是 @optional 还是 @required ,在委托方调用代理方法时都需要做一个判断,判断代理是否实现当前方法,否则会导致崩溃。
在iOS中代理的本质就是代理对象内存的传递和操作,我们在委托类设置代理对象后,实际上只是用一个id类型的指针将代理对象进行了一个弱引用。委托方让代理方执行操作,实际上是在委托类中向这个id类型指针指向的对象发送消息,而这个id类型指针指向的对象,就是代理对象。
通过上面这张图我们发现,其实委托方的代理属性本质上就是代理对象自身,设置委托代理就是代理属性指针指向代理对象,相当于代理对象只是在委托方中调用自己的方法,如果方法没有实现就会导致崩溃。从崩溃的信息上来看,就可以看出来是代理方没有实现协议中的方法导致的崩溃。
而协议只是一种语法,是声明委托方中的代理属性可以调用协议中声明的方法,而协议中方法的实现还是有代理方完成,而协议方和委托方都不知道代理方有没有完成,也不需要知道怎么完成。
由于代理对象使用强引用指针,引用创建的委托方对象,并且成为委托对象的代理。这就会导致委托对象的delegate属性强引用代理对象,导致循环引用的问题,最终两个对象都无法正常释放。
我们将委托对象的delegate属性,设置为弱引用属性。
weak 和 assign 是一种“非拥有关系”的指针,通过这两种修饰符修饰的指针变量,都不会改变被引用对象的引用计数。但是在一个对象被释放后, weak 会自动将指针指向 nil ,而 assign 则不会。在iOS中,向 nil 发送消息时不会导致崩溃的,所以 assign 就会导致野指针的错误 unrecognized selector sent to instance 。
所以我们如果修饰代理属性,还是用 weak 修饰,比较安全。
选择理由:新浪微博页眉页脚部分是经典的ios风格,在复杂的结构里也穿插着标签式导航的变体等其他形式,还有复杂多样的列表模式,在社交类APP里比较典型。
使用平台:iphone7
下图(左图)是新浪微博的首页,页眉是ios典型的导航栏,标题在中间,按钮分布在左右两边,因为是首页,不需要返回按钮。微博在这里放置了一个叫做“好友关注动态”的页面入口,用更多元的方式为用户推荐好友。
用的是舵式导航,置于中间突出位置的是发布按钮,点击后从底部飞出6个按钮,用户可以选择需要的发布方式。而原来的发布按钮“+”号,顺时针旋转变成了X号,点击X号又逆时针变回“+”号,同时页面回到动态列表。在这个用户最顺手的位置做了这样的交互,方便用户快速地在发布和浏览之间快速切换。这两个行为方式在社交类APP里是最核心的行为。
如上图所示的首页,有一个ios风格的内嵌式搜索框。刚进入首页时候是没有的,当页面刷新或下拉之后就会出现。因为用户无论是刷新或者下拉之后再返回,都是因为没有找到或者错过了自己想要的内容,这个时候提供搜索给用户,可以让用户自己检索想要的内容。
左边这个是经典的ios风格下拉框——带小三角的圆角矩形。右边这个做了一些改变:(1)当分组很多的时候,下拉框可以上下滚动,显示更多的内容。如果用tab导航的话,由于分组的名字是由用户起的,字段长度差异可能会比较大,会显得比较凌乱,而且首页的元素已经够多了,再用tab导航的话内容区域就更小了。下拉框则可以在不需要时候收起,节约空间。(2)在下拉框的底部有一个“编辑我的分组”按钮。这样做的优点在于不需要频繁地跳转到另一个页面,可以直接快速的切换分组,只有在要对分组进行编辑时,才会跳转到新的页面,在新的页面用户可以更专注于编辑分组,而不用担心误操作,毕竟下拉框空间有限,不方便直接编辑。再说回左图,有个小问题,就是图标用了雷达的图标。用户点开会发现除了雷达还有其他的2个功能,所以用雷达的图标代表所有的功能会有歧义,它正确的意思不是“雷达”而是“雷达等功能”。不喜欢用“雷达”的用户,也会比较难发现“扫一扫”和“打车”的功能。(现在最新版本的微博里右上角只有“扫一扫”和“打车”,并且默认显示扫一扫这个比较常用的功能)
微博中,下拉刷新和页面加载用的都是这样的菊花形加载,这种加载方式只表示状态,没有进度显示,如果用户长时间的等待的话,会感到不耐烦,不知何时才会加载完。但下拉刷新和页面加载都属于短时间的加载。在网络正常的情况下几秒之内就能完成加载。所以不需要显示进度,只需让用户明白正在加载即可。
微博的列表从整体的结构来说是以垂直列表为主,穿插着小图轮播式的“好友关注”和“相关文章”。但是往细了说,根据微博内容的不同,呈现的结构也稍有区别,这些设计模式同样也出现在其他社交类应用里:
1)纯文字微博
除此以外微博还有很多类型的单元格,都是在文字后插入其他的内容,例如图片、视频、链接等。
2)图片微博
文字后插入图片的形式是微博乃至大部分的社交APP里最常见的一种模式。如下图所示的是插有图片的微博。根据图片的数量不同,布局上会有些变化。只有一张图片时,按实际比例展示成缩略图,优点是展示出图片最真实的比例效果,缺点是当图片是竖图的时候布局不是特别好看。图片大于一张时会变成网格的布局,优点是在有限的空间里罗列尽可能多的内容,尺寸统一的方形图片和较小的间距,看起来比较有品质。有些爱玩的网友会利用这个特点进行自定义的设计,例如把9张局部的图拼成一张大图,更有趣味性和视觉冲击力。
值得一提的是,当图片为4张时,正好形成一个四宫格。这样就不会导致第二行只有一张图片了。不过在有些app里还做了更好的处理,就是把4宫格单张缩略图的尺寸比9宫格的单张尺寸做得略大一点。这样排版上会看起来更饱满。
3)视频微博
除了图片以外,插入视频也是非常常见的一种模式。如下图左图所示,微博的视频用一个相同的大图比例呈现,图片上会有一个播放按钮。但其实当视频拖动到页面中间时,视频会自动以无声的方式播放并显示进度。优点是可以让用户实时地看到视频内容,比较生动。
4)文章微博
上图右图所示的是发布文章所生成的微博,会以一张较大的封面图加上一行标题(图下方)的形式呈现。这种形式在一些电商的社区也是常常会看到,例如淘宝微淘里的“热文”。单张大图以统一的比例呈现,与单图微博(左上图)不同的是,它更有感染力,看起来更有档次,让人产生一种内容很专业的感觉。因为在信息量如此之大的微博(包括其他社区),用户往往是匆匆的浏览,如果不增强感染力,很难让用户驻足,甚至去浏览较长的内容。标题都在图片之下,可见图片才是吸引用户的首要元素。不过微博这里的设计,标题的存在感似乎太弱了一些。和图片的整体性有点欠缺,这样容易让用户产生只有一张大图的错觉而错过文章。
5)其他链接
除了以上所述的几种主流的单元格模式以外,有些微博在文末也会插入如下图所示的其他链接,可以是文章,也可以是商品、音乐等其他内容。以图片+标题等内容的形式呈现。比起纯文字来更生动,还可以知道链接的属性,例如音乐的话上面会有一个播放的图标之类的,缺点是感染力不够,优点是不会占太多空间,在有限的空间里给用途提供足够多的信息。
6)小图轮播的推荐列表
下图是微信的好友关注,其实不止是好友关注,还有推荐的文章等,都会以这种形式穿插在微博列表里,目的是向用户推荐好友或文章,以促进活跃度及强化社交。同时又不能影响用户正常浏览微博,所以用这种形式可以在有限的空间里推荐足够多的好友或文章,或其他信息给用户。缺点是在用户快速浏览时容易忽略。
1)下图左图是微博一级导航下的第二个tab——消息。同首页一样,标准的ios风格导航栏和内嵌式搜索,一进来的时候搜索是隐藏的,下拉才会显示。
页面内是标准的垂直列表。这种形式的优点是简洁清晰,冷静高效。用户到这里来往往是主动寻找一些内容,不像在首页常常是浏览的。所以这里不需要像首页那么复杂详细的列表,只需要简洁清晰的列表即可。根据用户从左至右、从上至下的阅读习惯,左边一排呈现的是图标或头像,用户可以一目了然。而“@我的”、“评论”、“赞”三个核心的社交功能图标置顶,之后的内容按时间由近及远排序,让用户可以随时见到最新的消息。
上图消息列表有2种单元格。一种是带箭头的二级列表,进去以后是子列表。这种形式的列表缺点是中间空白太多,有点浪费空间,而且不适用于层级太深,容易造成用户的厌倦。所以微博在这里只用作二级列表,再进去就是最后一层列表——微博列表,层级很浅。
另一种是没有箭头的列表,进去以后是对话框列表。优点是显示了一部分内容信息,用户可以快速的做出判断是否有兴趣查看,提高了使用效率。根据ios的操作习惯,左滑可以进行删除。缺点是呈现的内容太多不能再放置其他操作,比如箭头、控件等。所以这种形式最适合用于这种消息列表。
2)上图(右图)是“我”的界面。“我”与“消息”的界面一样,是一个标准的垂直列表页。由于这里只是功能的陈列,不像消息列表所要显示时间等信息,所以这里每个单元格的高度都不高,刚刚好容纳一行标题。“新的好友”、“我的相册”、“草稿箱”这些原始的功能层级都不深,而“微博钱包”、“微博运动”、“粉丝服务”、“粉丝头条”这些扩展的功能进去以后都是一个独立功能的首页。所以这里的内容层级都比较浅,适合这种带箭头的列表,可以直达目标页面;四个扩展功能后面还有灰色的小字用来引导用户;根据具体页面的类型还进行了分隔。所以整个页面看起来简洁清晰,冷静高效。
最后,这两个页面时都有一个共通的缺点,就是只有标题的单元格和有补充信息的单元格放在一起,布局上疏密明显,只有标题的单元格看起来很单薄,标题右边空荡荡的。而与其他信息的单元格对比之下就觉得密密麻麻的。
下图(左起第一张)是微博的“发现”页面。头部是ios经典的导航栏搜索。下面是轮播banner,这里用了轮播是为了在有限的空间里多呈现一些广告内容。再往下有两行入口图标,然后是微博列表。
微博列表模块的开头部分有个导航标签式的导航。如果页面上滑到了微博列表头部的位置,或者点击某个标签,这条标签式导航就会吸到页面顶部,变成标签式导航样式的分段式导航,见缝插针插进了导航栏。这是因为每个标签下面的内容信息量很大,还要分出第二层级,也就是吸到顶部以后
该导航下面出现的一行标签(见右图)。但是分段式导航的标签不宜太多,最好2-3个,微博用了4个,但所幸都是2个字的,看起来不算太拥挤,因为还有返回按钮,如果太拥挤的话,第一个标签离返回太近也会有歧议。布局上也会显得头部太重。
如右上图所示,“热门”、“榜单”、“视频”这三个板块都是微博内容,标签多于5个,所以做成了滚动式标签。
这个设计的优点在于灵活的运用了标签式导航的变化,让用户在没有明显的跳转的情况下,顺利的切换,不影响用户阅读的同时,承载了更大的内容量。缺点在于标签不宜太多,例如“热门”下的标签
有三十多个,后面的标签点击率会很低。并且如果不是根据用户的偏好进行排序的话,很有可能用户并不喜欢前面的内容,而喜欢在最后面,但他未必知道后面会有,也未必有耐心浏览到最后。
而最后的“头条”是用户可以自己定制的新闻内容,所以只放了4个优先级最高的,最后一个“更多”点击后进入“全部频道”(见上图右图),可以调整优先级,或者选择想去的频道。与底部导航栏一样的是,关闭按钮还是在底部,这样方便用户快速地回到头条页面。缺点同样也是标签过多容易造成用户的困惑。还有,不是在原标签下直接展开的,而是滑出一个浮层,所以可能会有点跳出感。但比起滚动式标签还是好一点,因为这种网格式布局的标签列表,把每一个标签都平等清晰的呈现给用户,便于用户快速的选择,而不用反复操作滑动去找不确定是否会有的标签。
1)下图是“我”里的“我的赞”。页眉也是典型的ios风格。标题在中间,右边是ios风格的“更多”(安卓是竖着的,之后分析安卓的app时候会有图),左侧是返回,并且带有上一级的标签,即“我”。这页的标签式导航是一个典型的标签式导航,并且一直置顶。无论页面如何滚动,它一直都在,用户可以便捷的再不同类目之间切换。
2)点击三个点的“更多”按钮从底部浮现选项,可以选择“刷新”或“返回首页”。这里只有2项,其实也可以做成2个按钮放在右上角。之所以这样做,好处首先是给用户更大的点击空间,避免误操作。还有就是页眉的布局不至于太挤。缺点就是需要多点一步。并且在上面点击后从底部浮出浮层的话用户的操作幅度有点大。但这和首页的下拉框是有区别的,下拉框主要是同级页面间的切换或者功能的切换。而这里是显示更多操作,所以也不适合用下拉框。
在数学和逻辑学中,单例定义为” 有且仅有一个元素的集合 “,在无论什么情况下,获取到的都是同一个值。在程序中,单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。这个方法应该是类方法,阻止所有想要生成对象的访问,避免一个全局使用的类频繁地创建和销毁。
static uniqueInstance 是 Singleton 中的唯一实例, static sharedInstance 将它返回给客户端。通常, shareInstance 会检查 uniqueInstance 是否已经被实例化,如果没有,会生成一个实例然后返回 uniqueInstance 。
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
只要应用程序需要集中式的类来协调其服务,这个类就应该生成单一的实例,而不是多个实例。
代理模式:完成委托方的任务,需要声明代理对象和指定代理,相对于block,在需要传递参数的传值时优先考虑代理。
代理是一对一的关系(1个对象只能通知1个对象发生了什么事)。
应用场景:不同类之间的传值与回调。
观察者模式(通知机制,KVO机制):观察者模式本质上是一种发布-订阅模型,用以消除具有不同行为的对象之间的耦合,通过这一模式,不同对象可以协同工作。
通知是一对多的关系(1个通知可以发送给多个通知接受对象)。
应用场景:监听设备状态,自定义键盘时监听键盘的弹出和隐藏。
单例模式:可以保证App在程序运行中,一个类只有唯一个实例。
系统中的单例:UIApplication(应用程序实例)、NSNotificationCenter(消息中心)、NSFileManager(文件管理)、NSUserDefaults(应用程序设置)、NSURLCache(请求缓存)等。
应用场景:功能集中管理的模块可以封装为单例,方便外界调用。
策略模式:定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
MVC(Model View Controller):
model:数据层
view:视图层,负责页面展示
Controller:控制视图层与数据层的关联,
MVVM(model view viewModel):
Model: 数据层,不包含逻辑
View:与用户直接交互,只需处理触发事件后的转发,和告诉他如何显示
ViewModel:跟踪view的事件,处理model层传递的数据;公开方法、属性,让view保持最新的状态
iOS开发就是为装有iOS系统的设备完成应用软件或游戏软件的开发,ios开发的设计模式有代理模式、观察者模式、MVC模式、单例模式、策略模式和工厂模式。