一、六大原则
- 单一职责:一个类,应该仅有一个引起它变化的原因。即类有且仅有一个功能,切忌大包大揽。
- 依赖倒置:针对接口编程,依赖于抽象而不依赖于具体。以此降低耦合,它是开闭原则的基础。
- 开闭原则:类、模块、函数对拓展开放对修改关闭。即代码功能拓展尽量实现热插拔而非修改原有代码。
- 里式替换:所有引用父类的地方必须能透明使用其子类。即子类可以扩展父类的功能,但不能改变父类原有的功能。
- 接口隔离:一个类对另一个类的依赖应该建立在最小接口上。
- 迪米特法则:一个对象应当尽可能少地与其他对象发生相互作用。
二、UML图
在UML类图中,常见的有以下几种关系:
- 泛化(Generalization)继承
- 实现(Realization)实现接口
- 依赖(Dependency) 局部变量、方法形参
- 关联(Association)成员变量(平等关系)
- 聚合(Aggregation)成员变量(has-a 关系,整体不拥有部分的生命周期)
- 组合(Composition)成员变量(contains-a 关系,整体拥有部分的生命周期)
图标示例:
2.1 泛化(Generalization)
继承
ClassB继承ClassA
2.2 实现(Realization)
实现接口
ClassB实现InterfaceA接口
starUML是如上表示,标准是虚线+实箭头
2.3 依赖(Dependency)
局部变量、方法形参
class Person{
fun buyCar(count:Int){
val car = Car()
car.buy(count)
}
}
2.4 关联(Association)
成员变量(平等关系)
class Person{
val car = Car()
fun buyCar(count:Int){
car.buy(count)
}
}
2.5 聚合(Aggregation)
成员变量(has-a 关系,整体不拥有部分的生命周期)
class GooseGroup(var goose: Goose) {}
2.6 组合(Composition)
成员变量(contains-a 关系,整体拥有部分的生命周期)
class Goose {
var wings: Wings
init {
wings = Wings()
}
}
关联、聚合、组合需要结合上下文来判断。
几种关系的强弱程度:
泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖
三、设计模式
创建型模式
1)单例模式
定义:保证一个类仅有一个实例供全局使用。
常见的实现方式有:懒汉、饿汉、double check、静态内部类、枚举。
保证线程安全+懒加载:推荐double check 或者 静态内部类两种方式
double check:
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){
}
public static Singleton getInstance() {
if (singleton== null) {
//首先通过synchronized来保证同一时刻只有一个线程能操作
synchronized (Singleton.class) {
//拿到锁之后还需要再判一次空,可能之前持锁线程已经创建了实例了
if (singleton== null) {
//singleton是引用类型,不具备原子性,因此可能发生指令重排。
//正常情况:实例化对象的流程:
//1.在堆上开辟空间
//2.属性初始化
//3.将栈上空间指向堆。
//正常情况是1->2->3 ,重排可能为1->3->2
//由于3步骤先执行,singleton已经不为空了,这时候其他进程访问getInstance直接return 对象,但是当前初始化并没有完成,出现问题。因此可以使用volatile来保证有序性,防止指令重排。
singleton= new Singleton();
}
}
}
return singleton;
}
}
静态内部类:
public class Singleton {
private Singleton(){
}
//延迟加载:静态内部类与外部类没有绑定关系,只有被调用到才会装载
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
//线程安全:静态初始化由虚拟机保证线程安全。Java 类加载的初始化过程中,编译器按语句在源文件中出现的顺序,
//依次自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并产生 () 方法,
//虚拟机会保证一个类的()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,
//那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕。
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
使用区别:静态内部类这种形式不支持传参,传参的情况下可以选择double check
2) 工厂三兄弟:简单工厂、工厂方法、抽象工厂
定义:对对象的实例化进行统一管理。
- 简单工厂:一个电脑工厂生产苹果电脑、惠普电脑、联想电脑。
- 工厂方法:对电脑工厂进行拆分,苹果电脑工厂生产苹果电脑、惠普电脑工厂生产惠普电脑。
- 抽象工厂:引入产品簇概念,苹果工厂生产苹果手机、苹果电脑、苹果平板,华为工厂生产华为手机、华为电脑、华为平板。
3)建造者模式
定义:将一个对象的构建与表示分离,一种更为优雅的对象属性赋值写法。
public class Computer {
public String cpu;
public String memory;
public Computer() {
throw new RuntimeException("can't init");
}
private Computer(Builder builder) {
cpu = builder.cpu;
memory = builder.memory;
}
public static final class Builder {
private String cpu;
private String memory;
public Builder() {
}
public Builder cpu(String val) {
cpu = val;
return this;
}
public Builder memory(String val) {
memory = val;
return this;
}
public Computer build() {
return new Computer(this);
}
}
}
public static void main(String[] args) {
Computer computer = new Computer.Builder()
.cpu("aaa")
.memory("ccc")
.build();
}
4) 原型模式
定义:克隆,用于创建重复对象。
- 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
- 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
public abstract class Shape implements Cloneable {
private String id;
protected String type;
abstract void draw();
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
public class Rectangle extends Shape {
public Rectangle(){
type = "Rectangle";
}
@Override
public void draw() {
System.out.println("rectangle draw");
}
}
public class Square extends Shape {
public Square(){
type = "Square";
}
@Override
public void draw() {
System.out.println("square draw");
}
}
public class ShapeCache {
private static Hashtable shapeMap
= new Hashtable();
public static Shape getShape(String shapeId) {
Shape cachedShape = shapeMap.get(shapeId);
return (Shape) cachedShape.clone();
}
public static void loadCache() {
Rectangle rectangle = new Rectangle();
rectangle.id = "1";
shapeMap.put(rectangle.id,rectangle);
Square square = new Square();
square.id = "2";
shapeMap.put(square.id,square);
}
}
public static void main(String[] args) {
ShapeCache.loadCache();
Shape clonedShape = (Shape) ShapeCache.getShape("1");
System.out.println("Shape : " + clonedShape.type);
Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
System.out.println("Shape : " + clonedShape2.type);
}
结构型模式
1) 代理模式
定义:为其他对象提供一种代理以控制对这个对象的访问。
静态代理:在代码运行前就已经存在了代理类的class编译文件
public interface IShop {
void buy();
}
public class Tianmao implements IShop {
@Override
public void buy() {
System.out.println("购买");
}
}
public class Purchasing implements IShop {
private IShop mShop;
public Purchasing(IShop shop){
mShop=shop;
}
@Override
public void buy() {
mShop.buy();
}
}
public static void main(String[] args) {
IShop purchasing=new Purchasing(new Tianmao());
purchasing.buy();
}
动态代理:在代码运行时通过反射来动态的生成代理类的对象,并确定到底来代理谁。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicPurchasing implements InvocationHandler{
private Object obj;
public DynamicPurchasing(Object obj){
this.obj=obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result=method.invoke(obj, args);
return result;
}
}
public static void main(String[] args) {
IShop tianmao = new Tianmao();
//创建动态代理
DynamicPurchasing mDynamicPurchasing = new DynamicPurchasing(tianmao);
ClassLoader loader = tianmao.getClass().getClassLoader();
//动态创建代理类
IShop purchasing = (IShop) Proxy.newProxyInstance(loader, new Class[]{IShop.class}, mDynamicPurchasing);
purchasing.buy();
}
2) 装饰
定义:通过组合而非继承的方式,动态的来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
3) 外观
定义:通过一个外观类使得整个系统的结构只有一个统一的高层接口,这样能降低用户的使用成本。
4) 享元
定义:对象池的概念
行为型模式
1) 策略
定义:使得策略可独立于使用它的客户而独立变化。
2) 模板
定义:父类定义抽象方法框架,将具体实现延迟到子类去执行,使得子类不能改变基本框架,但是可对特定步骤做差异化实现。
3) 观察者
定义:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。