类关系
- 依赖
依赖关系使用虚线加箭头表示。
依赖关系在代码体现为方法入参、方法返回、局部变量、静态方法调用。- 关联
关联关系使用实线加箭头表示,类之间的关系比依赖要强。
依赖关系在代码体现为类成员变量。
从关系的生命周期来看,依赖关系是仅当类的方法被调用时而产生,伴随着方法的结束而结束。关联关系当类实例化的时候产生,当类对象销毁的时候关系结束。相比依赖,关联关系的生存期更长。- 聚合
聚合关系使用实线加空心菱形表示。聚合用来表示集体与个体之间的关联关系
聚合关系在代码上与关联关系表现一致,都是类成员变量- 组合
组合(又叫复合)关系使用实线加实心菱形表示,用来表示个体与组成部分之间的关联关系。
组合关系在代码上与关联关系表现一致,都是类成员变量。- 泛化
泛化指的是类与类之间的继承关系和类与接口之间的实现关系。
继承关系使用直线加空心三角形表示。
类接口的实现关系使用虚线加空心三角形表示
聚合和组合的对比:
- 聚合关系没有组合紧密
聚合关系的类具有不同的生命周期。
组合关系的类具有相同的生命周期。
聚合类的构造函数中包含另一个类的实例作为参数,因为构造函数中传递另一个类的实例;组合类的构造函数包含另一个类的实例化,另一个类在构造函数中进行实例化,因此两者紧密耦合在一起,同生同灭。- 信息的封装性不同
在聚合关系中,客户端可以同时了解聚合关系的两个类,因为他们是独立的。
在组合关系中,客户端只认识组合类,不知道被组合类的存在,被组合类被严密地封装在组合类中。
理解聚合与组合的区别,主要在于聚合的成员可独立,组合的成员必须依赖于整体才有意义
SOLID原则
- 单一职责原则
SRP(Single-Responsibility Principle)
一个类,只包含单一职责,有且只有一个原因导致它变更
实现高内聚、低耦合的指导方针- 开闭原则
OCP(Open - Closed Principle )
对扩展开放,对修改关闭
实现开闭原则的关键是抽象化、封装可变性因素- 里式替换原则
LSP(Liskov Substitution Principle)
任何基类可以出现的地方,子类也可以出现- 接口隔离原则
ISP(Interface Segregation Principle)
客户端不应该依赖那些它不需要的接口- 依赖倒转原则
DIP(Dependency-Inversion Principle)
要依赖抽象,而不要依赖具体的实现;高层模块不依赖于底层模块,二者共同依赖于抽象。抽象不依赖于具体,具体依赖于抽象
其它原则
- 迪米特原则
Demeter Principle,最少知道原则
一个对象应当对其他对象有尽可能少地了解,简称类间解耦- 合成/聚合复用原则
CARP(Composite/Aggregate Reuse Principle)
要尽量使用对象组合,而不是继承关系达到软件复用的目的
设计模式
创建型设计模式
提供创建对象的机制, 能够提升已有代码的灵活性和可复用性。
- 单例(Singleton)
确保一个类只有一个实例,并提供该实例的全局访问点。
如果不需要延迟加载单例,使用枚举或者饿汉式,枚举比饿汉式好。
如果需要延迟加载,可以使用静态内部类或者懒汉式,静态内部类比懒汉式好。
双重检测锁方式,因为JVM本质重排序的原因,可能会初始化多次,不推荐使用- 简单工厂(Simple Factory)
它把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个具体子类来实例化,这样做能把客户类和具体子类的实现解耦,客户类不再需要知道有哪些子类以及应当实例化哪个子类- 工厂方法(Factory Method)
它定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类- 抽象工厂(Abstract Factory)
抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂方法模式只是用于创建一个对象,这和抽象工厂模式有很大不同- 生成器(Builder)
封装一个对象的构造过程,并允许按步骤构造- 原型(Prototype)
使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象
结构型设计模式
如何将对象和类组装成较大的结构, 并同时保持结构的灵活和高效
- 外观
也叫门面模式,提供了一个统一的接口,用来访问子系统中的一群接口,从而让子系统更容易使用- 适配器
将一个类的接口, 转换成客户期望的另一个接口。
适配器让原本接口不兼容的类可以合作无间。
对象适配器使用组合, 类适配器使用多重继承- 桥接
通过将实现和抽象放在两个不同的类层次中而使它们可以独立改变- 组合
允许你将对象组合成树形结构来表现"整体/部分"层次结构. 组合能让客户以一致的方式处理个别对象以及对象组合- 装饰
动态地将责任附加到对象上, 若要扩展功能, 装饰者提供了比继承更有弹性的替代方案- 亨元
利用共享的方式来支持大量细粒度的对象,这些对象一部分内部状态是相同的。 它让某个类的一个实例能用来提供许多虚拟实例- 代理
为另一个对象提供一个替身或占位符以控制对这个对象的访问。
代理模式
- 静态代理
每个需要代理的对象都需要自己重复编写代理 - 动态代理
JDK动态代理,使用反射完成代理,目标类必须实现接口
public class InvocationHandlerImpl implements InvocationHandler {
// 这其实业务实现类对象,用来调用具体的业务方法
private Object target;
// 通过构造函数传入目标对象
public InvocationHandlerImpl(Object target) {
this.target = target;
}
//动态代理实际运行的代理方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用开始处理");
//下面invoke()方法是以反射的方式来创建对象,第一个参数是要创建的对象,第二个是构成方法的参数,由第二个参数来决定创建对象使用哪个构造方法
Object result = method.invoke(target, args);
System.out.println("调用结束处理");
return result;
}
}
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
// 被代理对象
UserDao userDaoImpl = new UserDaoImpl();
InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(userDaoImpl);
//类加载器
ClassLoader loader = userDaoImpl.getClass().getClassLoader();
Class<?>[] interfaces = userDaoImpl.getClass().getInterfaces();
// 主要装载器、一组接口及调用处理动态代理实例
UserDao newProxyInstance = (UserDao) Proxy.newProxyInstance(loader, interfaces, invocationHandlerImpl);
newProxyInstance.save();
}
}
Cglib动态代理,使用ASM字节码完成代理,目标类可以不用实现接口,目标类不能是final类,私有方法不能代理。
public class CglibProxy implements MethodInterceptor {
private Object targetObject;
// 这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了动态代理
public Object getInstance(Object target) {
// 设置需要创建子类的类
this.targetObject = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
//代理实际方法
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("开启事物");
Object result = proxy.invoke(targetObject, args);
System.out.println("关闭事物");
// 返回代理对象
return result;
}
}
public class Test {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
UserDao userDao = (UserDao) cglibProxy.getInstance(new UserDaoImpl());
userDao.save();
}
}
Javassist动态代理
应用场景:
- Spring AOP
- 日志打印
- 异常处理
- 事务控制
- 权限控制。
行为型设计模式
负责对象间的高效沟通和职责委派
- 责任链
你可以为某个请求创建一个对象链. 每个对象依序检查此请求并对其进行处理或者将它传给链中的下一个对象- 策略
定义了算法族, 分别封闭起来, 让它们之间可以互相替换, 此模式让算法的变化独立于使用算法的客户- 模板方法
在一个方法中定义一个算法的骨架, 而将一些步骤延迟到子类中. 模板方法使得子类可以在不改变算法结构的情况下, 重新定义算法中的某些步骤- 命令模式
将"请求"封闭成对象, 以便使用不同的请求,队列或者日志来参数化其他对象. 命令模式也支持可撤销的操作- 观察者
在对象之间定义一对多的依赖, 这样一来, 当一个对象改变状态, 依赖它的对象都会收到通知, 并自动更新- 访问者
当你想要为一个对象的组合增加新的能力, 且封装并不重要时, 就使用访问者模式- 状态
允许对象在内部状态改变时改变它的行为, 对象看起来好象改了它的类- 解释器
使用解释器模式为语言创建解释器,通常由语言的语法和语法分析来定义- 迭代器
提供一种方法顺序访问一个聚合对象中的各个元素, 而又不暴露其内部的表示- 中介者
使用中介者模式来集中相关对象之间复杂的沟通和控制方式- 备忘录
当你需要让对象返回之前的状态时(例如, 你的用户请求"撤销"), 你使用备忘录模式
网友评论