三十六计GoF(Gang of Four,四人组)设计模式分为23种
| 范围/目的 | 创建型模式 | 结构型模式 | 行为型模式 |
|---|---|---|---|
| 类模式 | 工厂方法 | (类)适配器 | 模板方法解释器 |
| 对象模式 | 单例 原型 抽象工厂 建造者 | 代理 (对象)适配器 桥接 装饰 外观 享元 组合 | 策略 命令 职责链 状态 观察者 中介者 迭代器 访问者 备忘录 |
开闭原则
里氏替换原则
依赖倒置原则
接口隔离原则
迪米特法则
合成复用原则
如何解决类似“Service与某个具体Dao实现”耦合的问题?
将创建工作转移出来避免在Service中创建具体的Dao实现类,产生耦合
简单工厂模式,又叫做静态工厂方法模式,不属于 GoF 的23种设计模式之一,可以理解为工厂模式的一个特殊实现
依据依赖倒置原则,使用setter方法传递依赖关系,减少Service对工厂类的依赖,降低耦合
public class NewsServiceImpl implements NewsService {
private NewsDao dao;
public void setDao(NewsDao dao) {
this.dao = dao;
}
… …
}
简单工厂模式可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类
// 创建NewsDao实例的工厂方法
public static NewsDao getInstance(String key) {
switch (key) {
case "mysql":
return new NewsDaoMySqlImpl();
case "oracle":
return new NewsDaoOracleImpl();
case "redis":
return new NewsDaoRedisImpl();
default:
throw new RuntimeException("无效的数据库类型:" + key + " ,DAO获取失败");
}
}
要创建的产品不多且逻辑不复杂的情况,可以考虑简单工厂模式
简单工厂模式包含如下角色
增加新的产品需要修改,工厂方法的判断逻辑,不符合开闭原则
对简单工厂模式的进一步抽象,工厂方法模式的主要角色如下
创建抽象工厂接口
public interface AbstractFactory {
public NewsDao getInstance();
}
为不同NewsDao实现创建相对应的具体工厂
// 以生产NewsDaoMySqlImpl实例的工厂为例
public class MySqlDaoFactory implements AbstractFactory {
@Override
public NewsDao getInstance() {
return new NewsDaoMySqlImpl();
}
}
在测试方法中通过特定工厂生产相关的NewsDao实例
AbstractFactory factory = new MySqlDaoFactory();
// 改变具体工厂可创建不同产品
NewsDao dao = factory.getInstance();
优点
缺点
单一职责原则的体现,包含如下角色
实现方式总体上分为静态代理和动态代理
// 抽象主题接口 - 图片
public interface Image {
void display();
}
// 真实主题类 - 真实图片
public class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadImageFromDisk();
}
private void loadImageFromDisk() {
System.out.println("Loading image from disk: " + filename);
}
public void display() {
System.out.println("Displaying image: " + filename);
}
}
// 代理类 - 图片代理
public class ImageProxy implements Image {
private RealImage realImage;
private String filename;
public ImageProxy(String filename) {
this.filename = filename;
}
public void display() {
if (realImage == null) {
realImage = new RealImage(filename);
}
realImage.display();
}
}
// 调用代码
public class Client {
public static void main(String[] args) {
// 创建代理对象并显示图片
Image image = new ImageProxy("example.jpg");
image.display();
}
}

静态代理需要手工编写代理类,存在以下弊端
- 动态代理提供了运行时动态扩展对象行为的能力
- 能够依据给定的业务规则,在运行时动态生成代理类
从JDK 1.3版本开始引入
是面向接口的代理实现
核心API
如果被代理的目标对象不是通过接口进行定义的,JDK 动态代理将无法实施
需要使用继承和重写机制,CGLIB动态代理对于final类或final方法无能为力
从cglib https://github.com/cglib/cglib/releases下载所需的 jar 文件
主要 API