装饰器模式(Decorator)

装饰器模式用于在不修改原始类的基础上动态增加或覆盖方法,保持与原有类的层级关系。本文介绍了装饰器模式的概念、穷举法示例,如IO流包装,并探讨了在登陆方式扩展中的应用,以及在Spring框架下如何利用装饰器模式动态切换数据源。同时,对比了装饰器模式与适配器模式的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

装饰器模式(Decorator)

概述

  为了某个实现类在不修改原始类的基础上进行动态地覆盖或者增加方法,该实现保持跟原有类的层级关系。装饰器模式实际上是一种非常特殊的适配器模式,必须同宗同源(通过继承来实现)。
  装饰器和被装饰器都实现同一个接口,主要目的是为了扩展之后依旧保留OOP关系(同宗同源)。

穷举法

  IO流包装、数据源包装、简历包装

应用场景

登陆方式扩展

  还是上一章适配器模式的场景,需要扩展用户的登陆方式。如果采用装饰器模式,如下代码:

原登陆接口类

public interface ISigninService {
	//注册
    public ResultMsg regist(String username,String password);
	
	//登陆
    public ResultMsg login(String username,String password);
}

原登陆接口实现类

public class SigninService implements ISigninService {

    public ResultMsg regist(String username,String password){
        return  new ResultMsg(200,"注册成功",new Member());
    }

    public ResultMsg login(String username,String password){
        return null;
    }
}

扩展登陆接口,继承了原来的登陆接口

public interface ISigninForThirdService extends ISigninService {

    public ResultMsg loginForQQ(String openId);

    public ResultMsg loginForWechat(String openId);

    public ResultMsg loginForToken(String token);

    public ResultMsg loginForTelphone(String telphone,String code);

    public ResultMsg loginForRegist(String username,String password);

}

扩展登陆实现类,构造方法中注入了原登陆类

public class SigninForThirdService implements ISigninForThirdService {

    private ISigninService service;
    public SigninForThirdService(ISigninService service){
        this.service = service;
    }

    @Override
    public ResultMsg regist(String username, String password) {
        return service.regist(username,password);
    }

    @Override
    public ResultMsg login(String username, String password) {
        return service.login(username,password);
    }

    public ResultMsg loginForQQ(String openId){
        //1、openId是全局唯一,我们可以把它当做是一个用户名(加长)
        //2、密码默认为QQ_EMPTY
        //3、注册(在原有系统里面创建一个用户)
        //4、调用原来的登录方法
        return loginForRegist(openId,null);
    }

    public ResultMsg loginForWechat(String openId){
        return null;
    }

    public ResultMsg loginForToken(String token){
        //通过token拿到用户信息,然后再重新登陆了一次
        return  null;
    }

    public ResultMsg loginForTelphone(String telphone,String code){

        return null;
    }

    public ResultMsg loginForRegist(String username,String password){
        this.regist(username,null);
        return this.login(username,null);
    }

}

测试类

public class SigginTest {

    public static void main(String[] args) {

        ISigninForThirdService signinForThirdService = new SigninForThirdService(new SigninService());

        signinForThirdService.loginForQQ("xxssdsd");
    }
}

  上述代码的优点显而易见——原来的功能依旧对外开放,依旧保留;新的功能同样的也可以使用。
  事实上,若采用适配器模式对登陆类进行扩展,一般会在原有类中前加上@Deprecate注解,声明原有类不再建议使用。

spring中的装饰器模式

  在项目中我们经常会需要链接多个数据库。DAO访问SessionFactory的时候不得不在多个数据源中不同切换,问题就出现了:如何让SessionFactory在执行数据持久化的时候,根据客户的需求能够动态切换不同的数据源?我们能不能在Spring的框架下通过少量修改得到解决?是否有什么设计模式可以利用?

  1. 首先要在Spring的ApplicationContext中配置所有的DataSource。
  2. 然后DataSource类继承数据库Connection并进行扩展,这里用到的就是装饰器模式。
  3. 采用策略模式根据用户的需要动态切换数据库

装饰器模式与适配器模式区别

装饰器模式适配器模式
是一种特殊的适配器模式(保留层级关系)可以不保留层级关系
装饰者和被装饰者都要实现同一个接口适配者和被适配者没有必然的层级联系
主要目的是为了扩展,依旧保留OOP关系通常采用代理或者继承形式进行包装
满足is-a的关系(是不是)满足has-a(有没有)
注重的是覆盖、扩展注重兼容、转换
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值