单一职责原则(代码中每个类只做单一的事情),开闭原则(对修改关闭,对扩展开放),依赖倒置(面向接口编程),合成复用(优先使用组合关系,少用继承关系)
设计模式的类型:
按照功能分为三类23种:
- 创建型(5种):工厂模式、抽象工厂模式、单例模式、原型模式、构建者模式
- 结构型(7种,类的呈现,让类变得大家都认识):适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式
- 行为型(11种):模板方法模式、策略模式、观察者模式、中介者模式、状态模式、责任链模式、命令模式、迭代器模式、访问者模式、解释器模式、备忘录模式。
工厂模式 抽象工厂模式
1 2 3 4 5 6 7 8 9 10 11 12
| public class AnimalFactory { public static Object createObject(String name) { if ("cat".equals(name)) { return new Cat(); } else if ("dog".equals(name)) { return new Dog(); }... else { return null; } } }
|
万能类,但是代码都是写死的,硬编码。
第一种思路:
优化方向:配置文件。
1 2 3 4 5 6 7
| public static Object getBean(String name) { Map<String, Object> map = new HashMap<>(); Object object = map.get(name); return object; }
|
第二种思路:通过不同的工厂实例,创建不同的产品实例。(抽象工厂模式)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public interface AnimalFactory { <T> T createAnimal(); }
public class CatFactory implements AnimalFactory { public Cat createAnimal() { return new Cat(); } }
public static void main(String[] args) { AnimalFactory catFactory = new CatFactory(); Cat cat = catFactory.createAnimal(); cat.eat(); }
AnimalFactory catFactory = new CatFactory(); Cat cat2 = (Cat) catFactory.createAnimal(); cat2.eat();
AnimalFactory dogFactory = new DogFactory(); Dog dag2 = (Dog) dogFactory.createAnimal(); dag2.eat();
|
猫工厂生产猫,狗工厂生产狗。
原型模式
对一个对象作为原型,对其进行复制、克隆,产生一个和对象类似的新对象。
- 浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,引用类型,指向的还是原对象所指向的。必须实现cloneable 接口。
- 深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class Prototype implements Cloneable, Serializable { private static final long serialVersionUID = 1L; private String string; private SerializableObject obj;
public Object clone() throws CloneNotSupportedException { Prototype proto = (Prototype) super.clone(); return proto; }
public Object deepClone() throws IOException, ClassNotFoundException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); } public String getString() { return string; } public void setString(String string) { this.string = string; } public SerializableObject getObj() { return obj; } public void setObj(SerializableObject obj) { this.obj = obj; } }
class SerializableObject implements Serializable { private static final long serialVersionUID = 1L; }
|
构建者模式
复杂的对象的构造,与它的表示分离,使用同样的构建过程可以创造不同的表示。构建者模式中存在以下4个角色:
- builder: 为创建一个产品对象各个部件指定抽象接口
- ConcreteBuilder: 实现Builder的接口构造和装配该产品的各个部件,定义并明确它所创建的表示,提供一个检索产品的接口。
- Director: 构造一个使用 Builder 接口的对象
- Product: 表示被构造的复杂对象。
- 导演类:按照一定的顺序/需求组装一个产品。
- 构造者类:提供对产品的个性化定制,最终创建出产品
- 产品类:最终的产品
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| public class StudentBuilder { private Student student = new Student(); public StudentBuilder id(int id) { student.setId(id); return this; } public StudentBuilder name(String name) { student.setName(name); return this; } public StudentBuilder age(int age) { student.setAge(age); return this; } public StudentBuilder father(String fatherName) { Father father = new Father(); father.setName(fatherName); student.setFather(father); return this; } public Student build() { return student; } }
public class BuildDemo { public static void main(String[] args) { StudentBuilder builder = new StudentBuilder(); Student student = builder.age(1).name("zhangsan").father("zhaosi").build(); System.out.println(student); } }
public class Student { private int id; private String name; private int age; private Father father; }
|
单例设计模式

饿汉式单例(推荐)
1 2 3 4 5 6 7 8 9 10
| public class Student1 { private Student1() { } private static Student1 student = new Student1(); public static Student1 getSingletonInstance() { return student; } }
|
懒汉式单例
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Student5 { private Student5() { }
private static class SingletonFactory { private static Student5 student = new Student5(); } public static Student5 getSingletonInstance() { return SingletonFactory.student; } }
|
线程安全问题,判断依据:
- 是否存在多线程 是
- 是否有共享数据 是
- 是否存在非原子性操作
原子性理解:只有数字赋值才是原子性的。比如:x=10;(原子性) y=x;(非原子性)
Java指令重排序:不影响结果的情况下,JVM会将程序进行优化执行(有可能执行顺序不是代码顺序),在单线程没有问题,在多线程会有问题。比如以下代码:
双重检查锁创建单例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class student { private volatile static Student student; private Student() {} public static Student getSingletonInstance() { if (student == null) { synchronized(Student.class) { if (student == null) { student = new Student(); } } } return student; } }
|
禁止Java指令重排序:volatile 修饰词。可见性保证(多线程的可见性是和主存(物理内存有关的))、禁止重排序
由于 CPU 虽然将 i++ 了高速缓存中 i 的值是11,但是还未写入主存,此时线程2访问 i 还是10. 高速缓存中的i值为不可见,如果i 用 volatile 修饰,表示,只要值改变立马写入主存中。保证了可见性。
双重检查锁 创建单例。
装饰设计模式
职责:动态的为一个对象增加新的功能
实现细节:
- 真实构件和装饰构件实现相同的接口,这样,客户端可以以与真实对象相同的方式同装饰对象交互。
- 真实对象:io流中的new FileInputSream()、new FileOutputStream()
- 装饰对象持有一个真实对象的引用,装饰对象接受所有客户端的请求,并把这些请求转发给真实对象,这样就能在真实对象调用前后增加新的功能。
- 装饰对象负责给真实对象增加新的责任。
使用场景:
- IO中输入流和输出流的设计
- Swing包中图形界面构件功能
- Servlet API中提供了一个request对象的包装类设计模式的实现类HttpServletRequestWrapper,该类增强了request对象的功能。
- Struts2中,request, response, session对象的处理
创建一个抽象组件ICar接口,并创建具体构建角色以及各个具体装饰角色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| public interface ICar { void move(); }
class car implements ICar { @Override public void move() { System.out.println("陆地上跑!"); } }
class superCar implements ICar { private ICar car; public SuperCar(ICar car) { this.car = car; } @Override public void move() { car.move(); } }
class FlyCar extends SuperCar { public FlyCar(ICar car) { super(car); } public void fly() { System.out.println("天上飞"); } @Override public void move() { super.move; fly(); } }
class WaterCar extends SuperCar { public WaterCar(ICar car) { super(car); } public void swim() { System.out.println("水里游"); } @Override public void move() { super.move; swim(); } }
class AICar extends SuperCar { public AICar(ICar car) { super(car); } public void autoMove() { System.out.println("自动跑"); } @Override public void move() { super.move; autoMove(); } }
public class Client { public static void main(String[] args) { Car car = new Car(); car.move(); ICar flycar = new FlyCar(car); flycar.move(); ICar watercar = new WaterCar(car); watercar.move(); ICar car2 = new WaterCar(new FlyCar()); car2.move; } }
|
图:
总结
装饰模式降低耦合度,动态的增加或者删除对象的职责,并且让需要装饰的具体的构建类可以独立变化,以便增加新的具体构建类和具体装饰类。
优点:
- 扩展对象功能,比继承灵活,不会导致类个数几句增加
- 可以对一个对象进行多次装饰,创造出不同行为的组合
- 具体构建类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构件子类和具体装饰子类。
缺点:
- 产生了很多小对象,大量小对象占据内存,影响性能
- 容易出错,调试排查麻烦
装饰模式和桥接模式区别:
两个模式都是为了解决过多子类对象问题,诱因不同,桥接模式是对象自身现有机制沿着多个维度变化,是既有部分不稳定,装饰模式是为了增加新的功能。
单粒设计模式
单粒设计模式的完美实现(静态内部类、双重检查锁)
抽象模板
需求:统计代码块运行时长
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public abstract class GetTimeTemplate { public long getTime() { long t1 = System.currentTimeMillis(); code(); long t2 = System.currentTimeMillis(); return t2 - t1; } public abstract void code(); }
|
子类必须实现钩子方法。才能使用功能。
策略模式
- 抽象策略模式:通常由一个接口或者抽象类
- 具体策略角色:包装了相关的算法和行为
- 环境角色:持有一个策略类的引用
案例演示:
抽象策略类:TravelStrategy
具体的策略:飞机、火车、自行车
拥有策略的容器:人 Person
人要履行,拥有策略类集合(坐飞机、坐火车、骑自行车)
应用:springmvc中的 RequestHandler 和 handler 的映射
适配器模式
作用:将一个类的接口转换成另外一个客户希望的接口
解决的问题就是一个标准和另一个标准不兼容的问题
解决方案有两种:
- 一个标准去匹配另一个标准
- 两个不兼容的标准,去找到一个兼容的标准。
应用:springmvc 中的 RequestAdapter 针对 Object 类型的处理器做适配。使之可以正常工作