结构型设计模式 - 1类之间的结构

前言

23种设计模式,分三大类,创建型、结构型、行为型。

  • 创建型总共有 5 个,分两次记,第一次关注工厂,第二次关注单例、原型和建造者。
  • 结构型总共有7个,分三次记,第一次关注类之间的结构,第二次关注类之间的关系,第三次关注类的内部结构。

此类模式从程序的结构上实现松耦合,从而可以扩大整体的类结构。琢磨着大致分为三类:

结构型 模式
类之间的结构
类之间的关系
类的内部结构
适配器
桥接
装饰
组合
代理
外观
享元
  1. 类之间的结构
  • 适配器(adapter)【对象级别(1个对象)】

    • 使用一个已有的类,但又没有它的接口
    • 两个类功能相似,但接口不同
    • 双方都不太容易修改的时候
  • 代理(proxy)【功能级别(多个对象)】

    • 不关心业务细节,交由代理类完成
  • 外观(facade)【系统级别(很多个对象)】

    • 设计初期,考虑分层结构时,使用外观类建立层与层之间关系
    • 维护老系统时,让新系统与 外观类 交互,外观类与老系统交互
  1. 类之间的关系
  • 桥接(bridge)【各对象分类后,类类之间的桥】
    • 系统有多个维度的分类,每一种分类都有可能变化,那么就把多个维度分离出来让它们独立变化,减少它们之间的耦合
  • 组合(composite)【同时考虑整体与部分对象的方法】
    • 需求中有部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时
  • 享元(flyweight)【共享类】
    • 应用程序使用了大量的对象,这些对象一些共性可以共享时
  1. 类内部结构
  • 装饰(decorator)
    • 区分类的核心职责和装饰功能
    • 为已有功能动态地添加更多功能

1、Adapter

适配器模式:

  • 如果想用到很多类,又不想把这些类组合到目前的对象中,就可以定义一个接口,把这些类组合到这个接口里,你只需要调用这个接口,就可以调用这些类
«interface» IDoSomething Adapter Adaptee Client

步骤:

  • 确定 需要适配的类

    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

代理模式

«interface» 租房 代理 租房者 房东 implements implements
impl
impl
租房者
代理
租房
房东
租房

静态代理:

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时:

Alibaba Tencent Software Hardware

使用Bridge后:

Alibaba Tencent «abstract» CompanyBridge «interface» Department Software Hardware

步骤:

  • 把多个对象分离,共性的对象定义一个接口
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());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值