设计理念:
以
- 高聚集,低耦合;
- 对扩展开放,对修改关闭;
- 可扩展,可复用,易维护;
- 各施所职,相互协作,互不干涉,自己管自己
为理念
达到
取消一个功能
-
- 只需在主板块算法结构上注释对该功能的一个接口调用,并且不会影响到其它功能的正常运作
增加一个功能
-
- 只需在主板块类上组合一个功能实例变量,调其接口,无需操心以及直接操作有关其功能数据
编写过程中把基本不变的算法与需变更的算法分离,
利用组合抽象,根据协议接口编程。
其中算法分离以及组合抽象的方式需根据代码形势,以后需求变更,等因素而决定,
从而演变出一系列设计模式
(编译时期:
- 编译器在运行程序的时候会把各类文件编译为机器语言这个过程,也就是代码写的是什么就是什么
运行时期:
- 当代码真正运行到的时候才能确定具体内容,多态就好比一个方法接受一个泛型参数,只有在运行时真正编译才知道传入的具体类型,从而在编写的时候可以因不同情况传入不同适当的类型,达到多态。)
装饰者:包装一个对象,以提供新的行为
状态: 封装了基于状态的行为,并使用委托在行为之间切换
迭代器:在对象的集合之间游走,而不暴露集合的实现
外观: 简化一群类的接口
策略: 封装可以互换的行为,并使用委托来决定使用哪一个
代理: 包装对象,以控制对此对象的访问
工厂方法:由子类决定要创建的具体类是哪一个
适配器:封装对象,并提供不同的接口
观察者:让对象能够在状态改变时被通知
模板方法:由子类决定如何实现一个算法中的步骤
组合: 客户用一致的方式处理对象集合和单个对象
单件: 确保有且只有一个对象被创建
抽象工厂:允许客户创建对象的家族,而无需指定他们的具体类
命令: 封装请求成为对象
设计原则:
· 1.找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起;
· 2.针对接口编程,而不是针对实现编程;
· 3.多用组合,少用继承
· 4.为交互对象之间的松耦合设计而努力
· 5.依赖抽象,不要依赖具体类
· 6.最少知识原则:只和你的密友谈话
· 7.由基类主控一切,当需要时,自然去调用子类。
· 8.一个类应该只有一个引起变化的原因,每个类应保持单一责任
策略模式:(定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。)
声明各种行为接口协议,实现各种遵循行为接口协议的具体行为类(算法类),在主体中有的只是各种行为抽象对象,在具体使用时才赋上具体行为对象。
(通过算法族实现算法协议组合到产品基类中,在子类初始化或方法传参数时确定具体算法,达到可扩展,少用继承多用组合,重复利用算法代码,避免子类经常需要复写基类方法等目的)
观察者模式:(在对象之间定义一对多的依赖,这样当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。)
声明主题接口协议(供观察者注册的接口,撤销注册接口,发起通知接口),声明观察者接口协议,让主题知道观察他的所有对象都遵循这个观察者协议,都有这些接口。具体主题类(一般为单例模)遵主题口协议并且内部有个数组保存所注册的观察者对象,发起通知时便可遍历数组拿到观察者对象调用他们的观察者协议接口。
(该模式可通过增加观察者而扩展功能,而不需要修改主题,达到了对扩展开放,对修改关闭原则。)
装饰模式:
声明一个接口协议,该协议中的接口为将来装饰对象时所发生的接口,将会被装饰的对象遵循该协议,实现该协议中接口,到需要装饰他的时候,重新实现一个装饰者类,该类同样遵循该协议(装饰者与被装饰者遵循同一个协议为的是让他们都有相同的抽象行为方式)并且类内有一个被装饰者对象的引用并且在初始化时用被装饰者作为参数传进并保留起来,然后装饰者实现协议接口时便可以取到被装饰者也就是旧的接口方法的同时还可以添加上自己新的行为上去
id<behavior> class=[[Class1 alloc]init];
class=[[Decorate1_Class alloc]initWithClass1:class];
class=[[Decorate2_Class alloc]initWithClass1:class];
(该模式通过增加装饰者类对功能的扩展,达到对扩展开放,而不需要修改原有代码,达到对修改关闭,并且通过组合被装饰者,达到代码重用。由于装饰者模式需要大量组件子类在构造最终产物类之前往往需要多次装饰对象,因此多与工厂模式结合使用。)
简单工厂(非设计模式):
把需要根据不同情况生成不同类型对象的这部分抽出封装进一个工厂类中,该类中提供一个返回确定生成的对象的方法。
(该理念可以把因变化而改变代码程度降到最低并且集中。可把工厂类中返回具体对象的方法实现为类(静态)方法,也可以抽象为接口或基类用以有多个种类(流水线)下不同的产品这种情况。而下面的工厂方法则把控制种类(流水线)结合到抽象基类中放到了抽象方法去,让子类实现抽象方法,也就是它的每一个子类就是一个种类(流水线),能产生同类型不用种类的产品)
工厂方法模式:(抽象基类声明了一个返回具体组件对象的抽象方法,并且在基类内部的算法中调用该方法获取组件对象进行操作,而由子类实现该抽象方法决定供实例化的组件类范围有哪些相当于哪一个流水线的产品范围,也就是子类实现该方法时实际上是代替了简单工厂的范围的同时限定了供选择的产品族,因此这里无需与简单工厂结合使用。工厂方法让类把组合对象(产品)实例化推迟到子类。)
定义一个抽象基类把不变的部分实现,需要生成返回具体类型对象的部分写成抽象方法,基类中可调用该抽象方法拿到一个对象,就可以在基类对该对象操作一些不变的步骤,这样决定该对象具体类型就推延到子类实现该抽象方法的时候,又不妨碍基类中对它的操作。
(该模式其实和模板方法模式有点像,但是模板方法模式抽象基类中的抽象方法是实现功能时算法的抽象,而工厂方法模式抽象基类中的抽象方法是为了生成需要的组合具体对象,是生成对象的一种设计模式)
(ios实现抽象基类以及子类:声明一个接口协议(接口为基类中抽象化的接口),让父类遵循该接口协议,子类继承父类,同样子类也需要遵循该接口协议)
抽象工厂模式:(提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类)
声明一个接口协议,该协议的接口是一组返回具体类型对象的接口,然后具体工厂类遵循该协议,再实现具体的抽象方法,实现过程中针对该具体工厂生成具体的类型对象返回出去给别人使用。
——————————————工厂方法和抽象工厂的区别:——————————————————
工厂方法:是基类中有一个抽象接口返回具体类型对象,子类需实现该接口返回确定的类型对象;
抽象工厂:是声明一个接口协议,该协议的众多接口都是为返回具体类型对象,也就是负责创建一组产品的接口不像工厂方法只有一个抽象返回具体类型对象的接口,然后让具体工厂类遵循该协议,再实现具体的抽象方法,针对该具体工厂生成具体的类型对象,不像工厂方法是子类实现父类的抽象方法
针对该子类生成具体的类型对象。
单例模式:(确保一个类只有一个实例,并提供全局访问点)
编写类时,在类内部声明一个该类的静态对象,重写初始化方法时,判断该静态对象是否为空,是便为第一次生成需要对其分配内存,否则直接返回该对象,期间需要注意多线程安全问题,并且一个提供一个类方法直接获取该类对象。
命令模式:(将请求封装成对象,可以让你使用不同的请求,队列,或者日志请求来参数化其他对象。命令模式也可以支持撤销操作。)
已经有一群具体类(被马仔命令的类)中有各种操作接口,我们需要用不同命令管理控制这一群类,需要声明一个所有command(马仔)都需要遵循的接口协议,然后根据那群具体类中的每个操作设计一个对应的马仔command类,需要遵循那个command协议,并且类中有一个被命令对象的引用在初始化的时候被赋值, 然后实现该类遵循的协议抽象方法,在该协议抽象方法中有一个发起命令的抽象接口供老板叫马仔去发起命令从而调用具体类的对应方法。再设计一个老板类也就是控制器类,里面可以有一个数组用来保存众多马仔,并且提供外部方法只要传入下标就让马仔发起命令。如果逐个命令执行不爽,可以再宏马仔类(马仔领班),该类同样遵循那个协议,类内部有一个数组保存一组命令(马仔们)在初始化的时候被赋值,实现协议抽象接口时便让所以马仔都调用他们的抽象接口便可。这个马仔领班同样时id<马仔协议>类型,一样可以传入老板类让老板号召。至于撤销功能,让所有马仔遵循的协议添加一个撤销抽象方法,所有马仔实现他做他的反操作,让后老板类中有一个最近一个操作的马仔引用,在撤销的时候便调用该引用的撤销抽象协议方法便可。
适配器模式:(将一个类的接口,转换成客户期望的另一个接口,适配器让原本接口不兼容的类可以合作无间)
我们已经封装好一些控制类了,有一些新的类供我们使用,但是他提供的接口和我们原来写好的控制类
不兼容,我们又不想改封装好的类代码,那么适配器派上用场了,首先声明一个接口协议,该协议接口是根据迁就控制类而定的一套接口,然后设计一个适配器类遵循该协议,类中有一个被适配对象的引用并且初始化时赋值,然后适配器类就实现协议抽象接口,在实现的过程中调用引用对应的功能方法,这样就把改变让新建的适配器类承担了,不用动封装好的控制类了,控制类也可以像平时使用一样去使用适配器类从而间接使用了新的类功能了。
外观模式:(提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用)
有很多子系统的组件类,类中有很多操作方法,在主系统中想做一个动作,需要在主系统中拿到各种组件,然后逐个组件去执行他们对应的操作,这个主系统每次想做这个动作都得重新去拿到各种组件,然后逐个组件去执行他们对应的操作,这时外观模式出现了,把那一系列子组件动作封起来,新设计一个外观类,一个外观类对应一个主系统的动作,类中有刚那一系列子组件对象引用,并初始化时被赋值,
让后该外观类提供一个简洁的接口供主系统使用去执行想做的那个动作,外观类实现那个接口的时候就调用各种子组件的操作以完成主系统想要的该动作。这样每次主系统想做那个动作只需要执行那个外观类的那个简洁方法便可。
模板方法模式:(在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤)
我们对有共同操作方法但有的方法又有各自特点的类进行整理,写一基类抽出共同操作方法也就是对什么类来说都不变的方法写死在基类中,会变不同子类有不同特点的方法声明为抽象方法,如果仅仅这样不能算模板方法模式,应该并且基类有一个模板方法,该方法内指定了调用类内的方法包含具体方法与抽象方法的顺序,这样既定下了算法的顺序,又能让基类中抽象的接口在子类中才实现具体的算法。至于对模板方法挂钩,可以根据实际情况改变算法骨架也就是改变模板方法中的顺序,实现:在基类中添加一个抽象返回bool值的方法,然后基类中的模板方法中根据调用这个抽象方法的结果而去做不同的算法,因为这挂钩方法是个抽象方法,所以具体实现也是延迟到了具体子类中实现。这样特殊子类便可以有特殊的算法步骤了。
迭代器模式:(提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示)
用一个统一的方式hasnext方法和next方法去遍历任何数据结构的集合,那么迭代器出现了,声明一个迭代器都应该遵循的接口协议,其中有返回bool类型的hasNext抽象方法和放回id类型的next抽象方法,然后针对不同的数据结构集合的类型设计对应的具体迭代器类需要遵循那个协议,迭代器具体类中有一个该数据结构集合比如数组的引用并在初始化时赋值,还有一个记录位置的变量,在实现hasNext方法时根据记录位置的变量和集合的数量比较得出返回真假,next方法则根据记录位置的变量返回集合中下一个元素。有了迭代器,虽然因不同的类型数据集合有不同的具体迭代器类,但是其实他们都是id<迭代器协议>类型,使用迭代器具体类的用户也可以统一操作不同类型的具体迭代器类。简单数据结构集合一般可以用for in 循环达到迭代器功效。
组合模式:(允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合)
状态模式:(允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类)
有时候有一组动作,每个动作在不同的状态下有不同的处理方式,因为随时可能添加新状态,要管理起来就难了,所以状态模式出现了,先声明一个状态接口协议,协议内针对每个动作都写成一个对应的方法,然后每种状态设计一个对应的具体状态类遵循状态接口协议,实现各自状态中的不同动作操作,这样就把动作操作的管理放到了各自的状态中管理了,因为状态类中的动作方法中有可能需要对主系统的状态获取并设置(主系统中有各个具体状态对象其实他们也是抽象对象id<状态协议>),所以状态类中还有一个主系统对象的引用,并且在初始化时被赋值,然后设计主系统具体也就是这些状态的载体,首先类中包含了各种抽象具体状态对象和一个当前状态的对象,并在初始化的时候初始化他们,然后主系统中也有对应那组每个动作对应的方法,每个动作方法里面就执行当前具体状态类对象中对应的动作方法即可。这样动作的具体实现就放到了状态类中而不在主系统类中了。
代理模式:(为另一个对象提供一个替身或占位符以控制对这个对象的访问)
复合模式:(复合模式结合两个或以上的模式,组成一个解决反感,解决一再发生的一般性问题)
设计模式:(模式是在某情景下,针对某问题的某种解决方案)
模式分类:
创建型:(涉及到将对象实例化,这类模式都提供一个方法,将客户从所需要实例化的对象中解耦)
单例模式,抽象工厂模式,工厂方法模式
行为行:(只要是行为型模式,都涉及到类和对象如何交互及分配职责)
模板方法模式,命令模式,观察者模式,状态模式,策略模式,迭代器模式
结构型:(可以让你把类或对象组合到更大的结构中)
装饰者模式,适配器模式,复合模式,外观模式,代理模式
警告:过度使用设计模式可能导致代码被过度工程化。应该总是用最简单的解决方案完成工作,并在真正需要模式的地方才使用它。