七大设计原则 ​
强弱关系:依赖<关联<聚合<组合<实现<继承
核心思想 ​
找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
针对接口编程,而不是针对实现编程
为了交互对象之间的松耦合设计而努力
合成复用原则 ​
尽量使用合成/聚合来替代继承关系

单一职责原则 ​
接口隔离原则 ​
依赖倒置原则 ​
核心就是面向接口编程; 让细节的具体实现类去依赖(使用)抽象类或者接口;而不是让接口或抽象类去依赖细节的具体实现类.
里氏替换 ​
在面向对象编程语言的继承关系中,父类已经实现的方法,若子类进行修改,可能会产生问题.
使用继承虽然是比较方便的,但是会出现入侵,程序的可移植性降低,程序间的耦合性过高.
根据里氏替换原则,子类中尽量不要重写父类的方法; 所有引用父类的位置,要做到可以透明地使用子类的对象. 如果说子类还是需要父类的方法,可采用聚合,组合,依赖的方式.
开闭原则 ​
最基础最重要的原则
对扩展开放,相对修改关闭
迪米特法则 ​
类和类之间的关系越是复杂,他们的耦合性就会越高.
比如说 类 A依赖类B;那么类A就在内部 把类B的逻辑封装起来;不对外泄露信息.
只要两个对象之间有耦合关系,那么这两个对象就是朋友关系; 出现成员变量,方法参数,方法返回值中的类为直接的朋友; 只与直接的朋友通信.
一般不要将其他类作为局部变量使用.
UML类图 ​
依赖关系 ​
即一个类用到了另一个类, 例如A类中用到了B类;就说A类依赖B类.
可以是类的成员属性,方法的返回类型;方法接收的参数类型;在方法体中用到.
泛化关系 ​
泛化关系就是继承关系; 依赖关系特例
实现关系 ​
实现关系也是依赖关系的特例
关联关系 ​
关联具有导航性质;具有双向或者单向关系; 关联具有多重性; 一对一;多对一, 多对多
聚合关系 ​
聚合表示整体与部分的关系;整体和部分可以分开 是关联关系的特例
组合关系 ​
组合也表示整体与部分的关系;整体和部分不可以分开
人的身份证可以和人分开,但是头部作为人体的组成部分是不能分开的;
public class Person{
private IDCard card;
private Head head = new Head();
}
//身份证类;
public class IDCard{}
//头部类;
public class Head{}
设计模式分类 ​
设计模式是某类问题的通用解决方案
- 创建型模式:关注对象的创建。单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。
- 结构型模式:关注软件系统结构,使其更具扩展,更易管理维护。适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
- 行为型模式:关注方法的思考和设计。模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)
单例模式 ​
一个类把自己的构造方法隐藏起来; 这个类仅存在一个对象实例,且该类对外界只提供一个可以获取对象的方法.
单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(重量级对象),经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等).单例模式主要有五种:
饿汉式;懒汉式;双重检查;静态内部类;枚举
饿汉式 ​
静态常量 ​
public class StaticFinal {
private StaticFinal(){}
private static final StaticFinal ins = new StaticFinal();
public static StaticFinal getInstance() {
return ins;
}
}静态代码块 ​
class StaticBlock {
private StaticBlock(){}
private static StaticBlock ins;
static{
ins = new StaticBlock();
}
public static StaticBlock getInstance() {
return ins;
}
}- 使用饿汉式(静态常量版)在类加载的时候就完成实例化。避免了线程同步问题。
- 需要注意的是类加载的方式有很多种,不能保证用的是
getInstance()方法进行的类加载,那么此时的初始化singleton就没有懒加载的效果了;可能会浪费内存. - 优点:线程安全
- 缺点:不是懒加载,可能内存浪费
懒汉式 ​
线程不安全
class Singleton1{
private Singleton1(){}
private static Singleton1 ins;
public static Singleton1 getInstance() {
if(ins==null){
ins = new Singleton1();
}
return ins;
}
}优点:实现懒加载
缺点:线程不安全,破坏单例模式
懒汉式(线程安全) ​
class Singleton2 {
private Singleton2() {
}
private static Singleton2 ins;
public static synchronized Singleton2 getInstance() {
if (ins == null) {
ins = new Singleton2();
}
return ins;
}
//或者这种
//一个线程拿到锁后,其他线程都得排队等待
public static Singleton2 getInstance() {
synchronized (Singleton2.class) {
if (ins == null) {
ins = new Singleton2();
}
}
return ins;
}
}优点:懒加载线程安全
缺点:多线程环境下,每个线程都要排队,效率不高
//反射可以破解单例模式
public static void main(String[] args) throws Exception {
Class aClass = Singleton2.class;
Constructor declaredConstructor = aClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance();
System.out.println(Singleton2.getInstance());
System.out.println(o);
}双重检查懒加载 ​
//double check
class Singleton3 {
private Singleton3() {
}
//volatile 线程工作空间中产生变化能马上更新到主内存
private static volatile Singleton3 ins;
//即使一个线程先拿到锁,创建完对象,另外的线程可以直接return,不用等待
public static Singleton3 getInstance() {
if (ins == null) {
synchronized (Singleton3.class) {
if (ins == null) {
ins = new Singleton3();
}
}
}
return ins;
}
}减少同步方法执行的次数,兼顾懒加载的需求和多线程的效率,推荐使用
静态内部类懒加载 ​
class StaticInner{
private StaticInner(){}
//外部类加载的时候,静态内部类不会加载
private static class StaticIns{
private static final StaticInner INSTANCE = new StaticInner();
}
//只有需要的时候才会创建对象
public static StaticInner getInstance() {
return StaticIns.INSTANCE;
}
}即实现懒加载,即:我需要的时候再创建对象。又兼顾了线程安全,推荐使用
枚举单例 ​
枚举单例虽然跟饿汉式一样无法实现懒加载,但保证了线程安全,防止反射创建新对象,反序列化重新创建新对象
enum EnumSingleton{
INSTANCE
}