前言
23种设计模式,分三大类,创建型、结构型、行为型。
- 创建型总共有 5 个,分两次记,第一次关注工厂,第二次关注单例、原型和建造者。
- 结构型总共有7个,分三次记,第一次关注类之间的结构,第二次关注类之间的关系,第三次关注类的内部结构。
此类模式从程序的结构上实现松耦合,从而可以扩大整体的类结构。琢磨着大致分为三类:
- 类之间的结构
-
适配器(adapter)【对象级别(1个对象)】
- 使用一个已有的类,但又没有它的接口
- 两个类功能相似,但接口不同
- 双方都不太容易修改的时候
-
代理(proxy)【功能级别(多个对象)】
- 不关心业务细节,交由代理类完成
-
外观(facade)【系统级别(很多个对象)】
- 设计初期,考虑分层结构时,使用外观类建立层与层之间关系
- 维护老系统时,让新系统与 外观类 交互,外观类与老系统交互
- 类之间的关系
- 桥接(bridge)【各对象分类后,类类之间的桥】
- 系统有多个维度的分类,每一种分类都有可能变化,那么就把多个维度分离出来让它们独立变化,减少它们之间的耦合
- 组合(composite)【同时考虑整体与部分对象的方法】
- 需求中有部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时
- 享元(flyweight)【共享类】
- 应用程序使用了大量的对象,这些对象一些共性可以共享时
- 类内部结构
- 装饰(decorator)
- 区分类的核心职责和装饰功能
- 为已有功能动态地添加更多功能
1、Adapter
适配器模式:
- 如果想用到很多类,又不想把这些类组合到目前的对象中,就可以定义一个接口,把这些类组合到这个接口里,你只需要调用这个接口,就可以调用这些类
步骤:
-
确定 需要适配的类
public class Adaptee{ public void doOnething(){ } }
-
定义 适配器的接口
public interface IDoSomething { public void handleRequest(); }
-
定义适配器,把要适配的类组合进来
public class Adapter implements IDoSomething { private Adaptee adaptee; public Adapter(Adaptee adaptee){ this.adaptee = adaptee; } public void handleRequest(){ adaptee.doOnething(); } }
-
使用适配器 调用 被适配类
public class MyClass { public void doSomething(IDoSomething adapter) { adapter.handleRequest(); } }
-
doSometing
public static void main(String[] args) { MyClass myClass = new MyClass(); Adaptee adaptee = new Adaptee(); Adapter adapter = new Adapter(adaptee); // myClass的调用,不用关系 adaptee 的具体实现 myClass.doSomething(adapter) }
2、Proxy
代理模式
静态代理:
Static agent
-
实现了业务的分工,被代理对象(房东)可以只关心它的实现,不用操心公共(代理)的业务
-
公共(代理)业务方便扩展,不需要修改被代理对象(房东)
步骤:
- 需要代理的业务
public interface Service{
void doSomething();
}
- 被代理 对象
public class Server implements Service {
public void doSomething(){}
}
- 代理 对象
public class Proxy implements Service {
// 通过组合关联 被代理对象
private Server server;
public void Proxy(Server server){
this.server=server;
}
public void doSomething(){
doOtherthing();
server.doSomething();
}
public void doOtherthing(){ }
}
- 使用
Server server = new Server(); // 被代理业务
Proxy proxy = new Proxy(server); // 代理类
proxy.doSomething(); // 代理类 处理 业务
动态代理:
Dynamic agent
-
一个被代理对象对应一个代理对象,假如我们不想增加代理对象,而又想用代理,可以使用反射动态生成代理对象
-
使用反射的动态代理类代理的是一个接口,就是对应的一类业务,只要实现了这个接口的类都可以被代理
-
AOP的思想,底层就是动态代理
步骤:
- 需要代理的业务
public interface Service{
void doSomething();
}
public class Server implements Service {
public void doSomething(){
System.out.println("Server.doSomething");
}
}
- 使用
Proxy
类创建 动态代理类 - 定义动态代理类的 调用处理程序,实现
InvocationHandler
接口
public class MyProxy {
// 被代理的接口
private Object target;
public void setService(Object service) {
this.target = service;
}
// 动态生成代理类(此处未做异常处理)
public Object getMyProxy() {
InvocationHandler handler = new MyProxyInvHandler();
Class<?> proxyClass = Proxy.getProxyClass(
this.getClass().getClassLoader(),
target.getClass().getInterfaces());
Object instance = proxyClass.
getConstructor(InvocationHandler.class).
newInstance(handler);
return instance;
}
// 代理调用处理程序(此处未做异常处理)
class MyProxyInvHandler {
public Object invoke(Object proxy, Method method, Object[] args) {
doOtherthing();
Object result = method.invoke(target, args);
return result;
}
public void doOtherthing(){
System.out.println("proxy.doOtherthing");
}
}
}
- 使用(此处未做异常处理)
public static void main(String[] args) {
MyProxy myProxy = new MyProxy(); // 定义 代理
myProxy.setService(new Server()); // 制定 代理 业务
Service proxy = (Service) myProxy.getMyProxy(); // 生成 代理
proxy.doSomething(); // 代理 开始 服务
}
3、Bridge
桥接模式:
- 对象很多,有些对象可以归纳分类
- 但是如果我们分了两级以上的类别后,发现如果需要修改下级类别,维护起来很麻烦。这时需要考虑 各个类别 之间的关联,可以考虑抽象出一座桥,来建立这种关联
- 各个实现部分互相独立,符合单一职责原则
- 各个实现部分变化扩展,不需要修改其他部分,符合开放-封闭原则
未使用 Bridge时:
使用Bridge后:
步骤:
- 把多个对象分离,共性的对象定义一个接口
public interface Department { }
public class Software implements Department { }
public class Hardware implements Department { }
- 从多个对象里,总结出来一个抽象部分(桥)
- 抽象部分 通过组合的方式,把实现接口的 实现部分 组合进来
- 达到彼此 关联、分离 的目的
public abstract class CompanyBridge{
protected Department department;
public CompanyBridge(Department department){
this.department = department;
}
}
class Alibaba extends CompanyBridge { }
class Tencent extends CompanyBridge { }
- 使用
new Alibaba( new Software());
new Tencent( new Hardware());