设计模式中的设计原则:
1,单一职责原则
2,开闭原则:对扩展开放,对修改关闭,也即面对需求,对程序的改动是通过增加代码而不是改变原来代码
3,里氏替换原则:子类可以替换父类,程序不会出现错误
4,依赖倒置原则:底层模块依赖于上层模块,细节依赖于抽象
5,接口隔离原则:接口中仅包含为某一类用户定制的方法即可,不应该强迫客户依赖于那些它们不用的方法。
6,迪米特法则:类与类之间能不交互就不交互,将类与类之间的耦合减少到极致
7,合成(组合/聚合)复用原则:尽量使用对象组合而不是使用继承来达到复用的目的,通过组合聚合的方式可以减少类与类之间的耦合,其次才考虑继承,不要乱用继承,否则难以维护,这里的主要原因是破坏了封装性,由于继承子类拿到了父类的方法,暴露了细节,然而通过组合的方式将已有的对象放入到新对象中,内部细节不可见
合成复用原则案例:
写一个DBMySql类定义一个方法来连接MySql数据库,用户Customer类继承DBMySql,通过调用父类的方法来连接数据库,但是如果是MySql数据库改成了Oracle数据库,那么要把Customer类继承DBMySql改成继承DBOracle那么就违背了开闭原则
正确做法是:将连接DBMySql还是DBOracle类名放到配置文件中,读取配置文件时才反射生成对象,原来Customer类继承改成调用某个类方法
状态模式:
比如一个游戏人物有多个状态,行走,跑步,射击,蹲下,刚开始学习的时候会用一个枚举类型保存所有状态,然后设置一个标志位,然后一个switch来判断,这样的缺点是,万一要添加一个状态,就要修改原来代码,可以使用状态模式,一个状态为一个状态类,
我们创建一个context类,一个state类,让不同状态继承state类,context创建一个setState方法,形参是state,实参是new出state子类,在方法中得到子类对象,创建另一个方法调用state的抽象方法即可执行子类State方法
这里注意的是,在每个子类state中需要状态切换,那么需要调用Context类里面的方法来切换,所以每个子类中的构造函数里面传入参数context,this.context=context; 来指明是哪个类
但是这种设计模式缺点是新增加类会修改状态转换的源代码,不符合开闭原则
比如游戏logo界面跳转到游戏主界面,在跳转到战斗场景,跳转到游戏主界面,此时就可以用状态模式进行切换
外观模式:
中间添加一个服务员可以方便的管理不同人对于开水,茶具,茶叶的调度,减少耦合
中介者模式:
对于多对多进行通信的类,还有中介者模式,和外观模式十分类似,区别是
桥接模式:
对于球体sphere类和立方体cube类,要想调用OpenGL类的渲染方法,首先sphere类拿到OpenGL类的引用,然后创建一个方法,调用引用.方法名来实现。但是如果增加了一个directx类调用它的渲染方法,在sphere和cube类中先拿到directx的引用,然后再增加一个方法,通过引用.方法名来实现,这样的话每增加一个渲染类每个类都要修改
重构后:sphere类和cube类抽象并继承一个Ishape类,OpenGL和directx抽象出并继承一个IRenderEngine类,调用的话是IShape类调用IRenderEngine,
在Ishape中在构造方法中传入IRenderEngine并用引用保存,创建一个方法实现引用.方法名
在客户端调用时候渲染器类用多态new出来,作为参数放到Ishape子类的构造函数中
模板模式:
多个子类大部分流程一样,有个别细微不一样使用模板模式
享元模式:
对相同或者相似对象共享访问,实现内存的节约,比如围棋中那么多棋子,创建那么多对象浪费内存,我们让看上去都是每一个对象,实际上它们共享同一个享元对象,存储这些共享实例对象的地方称为享元池,针对每一个不同的字符创建一个享元对象,将其放在享元池中,需要时再从享元池取出。
享元分为内部状态和外部状态,内部部分是可以共享的部分,外部是不可以共享的部分
这个模式和工厂模式配合使用,一般在工厂类,初始化方法里放一个字典,add所有类型的对象,k为类型,v为new出来的对象,对象需要做成单例,如果为空才new不为空直接得到,再创建一个方法来根据类型取得对象,我们可以把这个字典或者hashMap看做享元模式的对象池
组合模式:
用处:一般用于递归电脑中的文件,比如杀毒,d盘中包括文件或者文件夹,通过递归来遍历整个树的所有节点。这里要把树下分为文件和文件夹两种类型,文件夹里面可以继续添加节点。
在组合模式中,文件类和文件夹类都要继承一个抽象类,抽象类包括四个方法,1,operation具体操作类方法,文件和文件夹都包含此方法,2,add节点
remove节点,getChild这三个方法让文件夹类去包括。当然在文件夹类中可以写个list来保存里面的子节点
最后要遍历的时候,写一个递归函数就行
命令模式
比如防御塔一下要生产一批小兵,那么在两者之间再加上一个invoker类,防御塔把命令发送给它即可,创建一个抽象command(命令)基类,包含一个抽象execute(执行)方法,创建一个receiver(接受者)类,在ConcreteCommand (具体命令)子类中的execute方法用执行receiver的特定方法,当然创建小兵的参数在该类的构造函数中获得,execute方法来调用小兵工厂类类创建小兵,在invoker中添加executeCommand方法来执行具体命令
观察者模式:
这样记:行人观察红绿灯的变化来判断行走方向,这种一个红绿灯来改变许多人行为的模式叫观察者模式.
定义一个通知者类,定义一个观察者类,观察者类写一个update函数用于当收到通知做出改变。在通知者类中用一个ArrayList保存所有的观察者。在创建添加,删除观察者的方法,再定义一个notify方法用于遍历ArrayList中所有观察者的update方法
单例模式:
两静态私有,一返回:
new 出对象私有化,注意在类中就通过静态new出来,别放到GetInstance函数中再new出来
构造函数私有化,注意构造函数没返回值
最后通过一个方法来返回对象
1 在使用时候,由于没有抽象层,也即没有父类,因此很难扩展,所以写单例模式的时候想好要不要扩展
2 很多时候把过多任务分配给单例类违背职责单一原则
加锁消耗资源,那么就判断需要new对象的时候再加锁,但是if instance==null判断完后可能另一个线程突然new了个对象所以加锁后还得再判断一次
饿汉式:
懒汉式:在程序加载的时候就静态new出了