目录
浅克隆创建的对象,如果修改它某个引用类型的某个属性的值,那会不会影响原来的对象?
设计模式六大原则
1.单一职责:一个类只负责一项职责。
(1) 降低类的复杂度,一个类只负责一项职责,类的可读性,系统的可维护性更高。
(2) 因需求变更引起的风险更低,降低对其它功能的影响。
2. 里氏替换:子类可以扩展父类的功能,但是不能改变父类原有的功能。
(1) 子类可以实现父类的抽象方法,不能覆盖父类的非抽象方法。
(2) 子类可以增加自己特有的方法。
(3) 子类的方法重载父类的方法时,方法的形参比父类方法更宽松。
(4) 子类的方法实现父类的抽象方法时,方法的后置条件(返回值)要比父类更严格。
3. 依赖倒置:高层模块不依赖于低层模块,二者通过抽象来依赖,依赖抽象,而不是细节。
(1) 依赖倒置原则的核心思想时面向接口编程。
(2) 底层模块尽量都要有抽象类或接口。
(3) 变量的声明类型尽量时抽象类或者接口。
(4) 使用继承时遵循里氏替换原则。
4. 接口隔离:客户端不应该依赖不需要的接口。
(1) 建立单一接口,尽量细化接口,接口中的方法尽量少。
(2) 为当个类建立专用接口,不要包含太多。
(3) 依赖几个专用的接口要比依赖一个综合的接口更灵活,提高系统的灵活性和可维护性。
5. 迪米特法则:降低类之间的耦合度,每个类尽量减少对其它类的依赖,尽量减少对外暴露的方 法,使得 功能模块独立,降低耦合。过分使用迪米特原则,会产生大量的中介和传递类,导致 系统复杂度变高。
6. 开闭原则:软件中的对象(类,模块,函数等)对于扩展应该是开放的,对于修改应该是封闭的。
(1) 当需求发生变化时,尽量扩展实体的应为来变化,不是通过修改已有的代码来实现变化。
(2) 低层模块的变化,必然有高层模块进行耦合,它并不意味着不做任何修改。
7. 总结
(1) 单一职责实现的类要职责单一。
(2) 里氏替换原则不要破坏类的继承体系。
(3) 依赖倒置原则要面向接口进行编程。
(4) 接口隔离原则设计接口的时候要精简单一。
(5) 迪米特法则要降低类之间的耦合度。
(6) 开闭原则对于扩展应该是开放的,对于修改应该是封闭的。
创建型/结构型/行为型
- 创建型设计模式:关注对象的创建。
- 结构型设计模式:关注类与类之间的关系,一般组合的方式优于继承,因为继承属于强依赖,不够灵 活。适配器,桥接,组合,装饰,外观,享元,代理等等,它们的核心套路都是再包一层。
- 行为型设计模式:关注对象和行为的分离(类和方法),也就是看方法到底放到哪里比较合适。
单例模式
是什么
- 单例模式是指整个应用程序中有且仅有一个实例,对象只能被创建一次。
- 线程池,数据库链接池,配置文件对象,IOC容器实例等都需要单例实现。
饿汉式
是什么
- 饿汉式单例类在类被加载时就将自己实例化,无须考虑多个线程同时访问的问题,确保实例的唯一性。
- 由于单例对象一开始就被创建,因此要优于懒汉式单例。
- 但是无论系统在运行时是否需要使用该单例对象,在类加载时该对象都会被创建。
- 因此从资源利用效率角度来讲,饿汉式单例不如懒汉式单例。
- 而且在系统加载时由于需要创建饿汉式单例对象,加载时间可能会比较长。
CLR来保障实现单例
- 比如利用静态构造函数,静态字段来实现的单例,都是由CLR保障的。
- 只不过静态构造函数创建的单例是在对象使用之前完成初始化并且只执行一次。
- 而静态字段创建的单例是在类型使用之前完成初始化并且只执行一次。
懒汉式
是什么
- 懒汉式单例类在第一次使用时创建,没有一直占用系统资源,实现了延迟加载。
- 但是必须要处理好多线程同时访问的问题,需要通过双重检测锁定等机制进行控制。
双检锁/Lazy实现单例
原型模式
应用场景
创建一个重量级的重复对象。
浅克隆
- 可以用object对象提供的MemberwiseClone方法,进行浅克隆。
- 浅克隆只是克隆内存的地址。
深克隆
- 可以用序列化和反序列化来进行深克隆。
- 深克隆不但可以克隆内存的地址,内存地址指向的值,也就是堆空间中的对象,也会被克隆。
浅克隆创建的对象,如果修改它某个引用类型的某个属性的值,那会不会影响原来的对象?
会,因为浅克隆只是克隆内存的地址。新克隆出来的对象内存地址指向的值,也就是堆空间中的对象,和原来的对象内存地址指向的值是一样的。
原型模式和单例模式的区别
原型模式是新的实例,如果创建对象需要一定成本的时候,需要原型模式。
享元模式
如果有现有的实例就不去创建,直接拿来用。
策略模式
- 策略模式主要是用在根据上下文动态去控制类的行为的一个场景。
- 一个方面可以解决多个if else判断带来的代码复杂性和维护性的问题。
- 另一方面,把类的不同行为进行封装,使得程序可以进行动态的扩展和替换,增加了程序的灵活性。
- 比如像支付路由这样一个场景,就可以使用策略模式来实现。
观察者模式
- 观察者模式主要是用在一对多的对象依赖关系的处理过程中,实现某一个对象状态变更之后的感知。
- 一方面可以降低对象依赖关系的耦合度,弱化依赖关系。
- 另一个方面,通过这种状态通知的机制,可以保证这些依赖对象之间的状态协同。
- C#里面的多播委托或者向事件里面注册多种方法都是观察者模式的体现。
简单工厂
- 就是为了转移对象的创建,转移矛盾,传入不同的枚举类型,创建不同的对象。
- 简单工厂是由一个工厂对象决定创建出哪一种产品类的实例。
工厂模式
- 工厂模式主要是为了扩展,屏蔽细节。
- 简单工厂中新增产品对象是直接修改工厂类的,它违反了开闭原则,所以需要工厂模式。
抽象工厂
- 多个对象的创建,是必须全部实现。抽象工厂多个对象的创建,工厂方法+抽象,
- 抽象是必须都实现的。抽象工厂就是强行加了一层抽象的约束,抽象工厂里面所生产的对象,他们是一个整体,是不可分割的。
- 抽象工厂可以生产多种产品,简单工厂/工厂模式只生产一种产品。
适配器模式
- 适配器模式主要是将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作, 也称做包装器(Wrapper)。
- 在适配器模式中组合是优于继承的,因为继承属于强依赖,任何父类的东西,子类必须有。
- 用组合的话要灵活一点,没有多余的负担,还可以把接口抽象为服务。
代理模式
- 代理模式就是给某一个对象提供一个代理对象,由代理对象控制对原对象的引用。
- 比如日志/异常/饿汉式的单例/缓存等。
- 代理模式也是AOP的一种体现。
责任链模式
是什么
- 使多个对象都有处理请求的机会,从而避免了请求的发送者和接收者之间的耦合关系,将这些对象串 成一条链,并沿着这条链一直传递请求,直到有对象处理它为止。
- 责任链模式是将处理不同逻辑的对象连接成一个链表结构,每个对象都保存下一个节点的引用。
实现原理
单向责任链
- 设计一个单向链表的上下文Context,保存链表的头(head)引用和尾(tail)引用
- 然后,在上下文中加入 Handler,也就是处理业务逻辑的节点类,每个Handler都保存了下一个执行 节点的引用,形成一条完整的执行链路。
双向责任链
- 它和单向链表的基本结构一致。
- 它只是在 Handler 中增加了对上一个节点的引用。
- 这样责任链就形成了一个执行闭环,就好比是环线地铁。
优点
- 实现了将请求与处理完全解耦。
- 请求处理者只需要关注自己职责范围内的请求进行处理即可,对于不是职责范围内的请求,直接转发 给下一个节点对象。
- 具备链式传递处理请求的功能,请求发送者不需要知晓链路的结构,只需要等待请求处理结果即可。
- 链路结构灵活,可以通过改变链路结构动态的新增或者删减责任。
缺点
- 如果责任的链路太长或者处理时间过长,会影响程序执行的整体性能。
- 如果节点对象存在循环引用,有可能会造成死循环从而导致程序崩溃。