设计模式入门概念通俗理解
设计模式
GoF:《设计模式:可复用面向对象软件基础》,收录23种design pattern。
设计模式的本质是面向对象设计原则的实际应用,是对类的封装、继承、多态以及类的关联和组合的充分理解。
正确使用设计模式的优点:
- 可以提高程序员的四位能力、编程能力和设计能力。
- 使程序设计更加标准化、代码编址更加工程化,使软件开发效率大大提高,从而缩短如那件的开发周期。
- 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。
设计模式的基本要素
- 模式名称
- 问题(应用环境)
- 解决方案(模板)
- 效果(优缺点,时间空间)
一种思维、一种态度、一种进步
基本分类:
-
创建性模式
单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式
-
结构型模式
适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式
-
行为型模式
模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、责任链模式、访问者模式。
OOP七大原则
- 开闭原则:对扩展开放,对修改关闭
- 里式替换原则:继承必须确保超类所拥有的性质在子类中仍然成立。(企鹅其它鸟类,企鹅不会飞,其它鸟类会飞。)
- 依赖倒置原则:要面向接口编程,不要面向实现编程。抽象不依赖细节,细节依赖抽象。
- 单一职责原则:控制类的粒度大小、将对象解耦、提高内聚性。类的职责单一,一个方法尽可能干好一件事。
- 接口隔离原则:腰围各个类建立它们需要的专用接口。
- 迪米特法则:只与你的直接朋友交谈,不要和陌生人说话。对于对象之间的关联,只与直接对象 A -> B - > C, 类B就中介朋友。降低类间耦合度。
- 合成复用原则:尽量使用组合或者聚合来关联,其次考虑使用继承关系来实现。
单例模式
饿汉模式
public class Hungry {
// 饿汉 开始就new 一个对象
private static Hungry instance = new Hungry();
// 可能会浪费许多空间
private byte[] waste = new byte[1024 * 1024];
// 构造器私有
private Hungry() { }
public static Hungry getInstance() {
return instance;
}
}
public class LazyMan {
// 懒汉模式 声明volatile避免指令重排
private volatile static instance = null;
// 等使用到资源才被加载
private byte[] waste = new byte[1024 * 1024];
// 构造器私有
private LazyMan() {
synchronized (LazyMan.class){
if (instance != null) {
thorw new RuntimeException("试图用反射破坏异常");
}
}
}
public static LazyMan getInstance() {
// 需要加锁 防止在多线程情况下 仍然new 出多个实例
// 双重检测
if (instance == null) {
synchronized (LazyMan.class){
if (instance == null) {
instance = new LazyMan();
}
}
}
return instance;
}
}
单例不安全,仍然可以在反射改变单例构造方法的访问属性,就可以去获得两个单例。
单例不是绝对的安全,仍然可以通过改变访问属性去创建多个单例。
枚举类的单例无法被破坏,枚举类没有无参构造函数,只有两个参数的有参构造。
单例模式的应用:
- Windows的任务管理器
- Windows的回收站
- 项目中读取配置文件的类,一般只用一个对象就够了
- 网站的计数器,使用单例保证同步
- 数据库连接池是单例的
- Servlet编程中每一个Servlet也是单例的
- Spring中每个Bean就是单例的。
工厂模式
实现了创建者和调用者的分离。
-
简单工厂模式
-
工厂方法模式
-
抽象工厂模式
满足七大原则的三大原则:
- 开闭原则:只扩展不修改
- 依赖倒转原则:面向接口
- 迪米特法则:只与你直接的朋友通信。
核心本质:
- 不再使用new来创建对象,使用工厂方法代替
简单工厂模式(静态工厂模式)
不修改代码没法做到新增车辆。
要是想要满足开闭原则 需要花费较大的代价。
增加新产品需要新增代码。
public interface Car {
void name();
}
public class Wuling implements Car {
@Override
public void name() {
sout << "五菱宏光"
}
}
public class Tesla implements Car {
@Override
public void name() {
sout << "Tesla"
}
}
public class CarFactory {
// 方法一 但是不满足 开闭原则
public static Car getCar(String name) {
if (name.eqauls("Tesla")) {
return new Tesla();
}
...
}
}
psvm {
// 1. new
// Car car = new Tesla();
// 2. Factory
Car car = Factory.gerCar("Tesla");
car.name();
}
工厂方法模式
为每一个对象增加一个工厂。支持增加任意产品。
与简单工厂模式的区别在与:多个工厂实现了工厂接口。
代码量增加许多。
public class Tesla implements CarFactory {
@Override
public void getCar() {
new Tesla();
}
}
psvm {
// 1. new
// Car car = new Tesla();
// 2. Factory
// Car car = Factory.gerCar("Tesla");
// car.name();
// method 满足开闭原则
Car car = new TeslaFactory.getCar();
}
根据设计原则:工厂方法模式
根据实际需求:简单工厂模式
实际应用:
- JDK中的Calendar的getInstance()方法
- JDBC的Connection对象的获取
- Spring中的IOC创建管理Bean对象
- 反射中Class对象的newInstance方法
抽象工厂模式
创建工厂的工厂。
抽象工厂提供了一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类
优点:
- 具体产品在应用层的代码隔离,无需关系创建的细节。
- 将一个系列的产品统一到一起创建
缺点:
- 规定了所有肯能被创建的产品集合没产品簇中扩展新的产品比较苦难
- 增加了系统的抽象性和理解难度
建造者模式
属于创建型模式,它提供了一种创建对象的最佳方式
用户只用给出指定的对象的类型和内容,建造者模式负责按顺序创建复杂对象(把内部细节隐藏起来)
例子:
- Director指挥Worker去建造(建地基,铺水泥,粉刷)最后一个Product房子
- 麦当劳服务员接受用户点餐返回一个套餐。
原型模式
以某个原型进行克隆。赋值粘贴。
Prototype
Cloneable接口
clone()方法
浅克隆:对象的属性没有克隆。Object.clone()
深克隆:对象的属性也进行了克隆。
应用:Spring Bean: 单例 + 原型模式
工厂模式 + 原型模式 : 工厂生产可乐每次都是克隆原配方来生产。
适配器模式
桥接模式
代理模式
静态代理模式
动态代理模式
动态代理的代理类是动态生成的,代理的是接口,不是一个特定的类
类型:
-
基于接口的
JDK动态代理
-
基于类的动态代理
cglib
-
java字节码:javasist
两个类需要掌握:
- proxy
- invocationHandler
优点: