Java 设计模式 装饰者模式

装饰者模式定义:

           动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。

在设计的时候,往往要给一个对象的功能进行一些修饰,对功能进行拓展和增强,以满足我们的需求。

案例分析:

         举个例子,最近流行歌曲比赛,什么《中国好声音》,《中国好歌曲》什么的,对于一个参赛者而言,就是唱歌,定义类如下:

public class Competitor {
 
    public void sing()
 
    {
 
        System.out.println("我唱唱唱......");
 
    }
 
}

 但是这个是远远不够的,你有一个好嗓门,也是需要包装的,一个裸唱、没有伴奏、没有伴舞的参赛者去比赛哪有什么竞争力啊!于是,我们要对这个参赛者进行包装,在他唱歌的时候加上舞蹈:

public class CompetitorDecorator1 extends Competitor {
    public void sing()
    {
        this.dance();
        super.sing();
    }
    private void dance()
    {
        System.out.println("偏偏起舞....");
    }
}

 加上舞蹈还不行,还要在唱歌的时候播放合拍的背景音乐:

public class CompetitorDecorator2 extends Competitor {
    public void sing()
    {
        this.playMusic();
        super.sing();
    }
    private void playMusic()
    {
        System.out.println("播放背景音乐......");
    }
}
 

 现在的选手都打感情牌,唱完歌后,介绍自己有多不幸,自己多努力啊……诸如此类,把评委和观众搞得稀里哗啦的,然后评分就蹭蹭地上去了:

publicclass CompetitorDecorator3 extends Competitor {
    public void sing()
    {
        super.sing();
        this.introduceBackground();
    }
    private void introduceBackground()
    {
        System.out.println("悲惨背景介绍,博取同情,赢感情牌....");
    }
}

以上对对象的装饰实现,是通过继承父类的方式,重写父类的方法,加上自己的装饰,强化相应的功能。

现在,我想将播放背景音乐和跳舞这两个装饰都用上,该怎么用呢? 相信很多人都会有这样的一个方法:继承CompetitorDecorator1,重写sing() 方法,将playMusic()方法加进去啊

public class CompetitorDecorator4 extends CompetitorDecorator1 {
    @Override
    public void sing()
    {
        this.playMusic();
        super.sing();
    }
    private void playMusic()
    {
        System.out.println("播放背景音乐......");
    }
}

是的,这样确实可以完成相应的功能。但是有没有觉得怪怪的呢?

           1.我们在CompetitorDecorator2内已经有了 playMusic() 代码片段,我们在CompetitorDecorator4内有和它完全一样的playMusic()代码片段,这个是不合适的,也是不可取的!

           2.如果这个选手比较有才,有五花八门的各种装饰,我们为此要增加相应多的装饰类;如果他在这方面有很深的造诣,把这些装饰发挥的淋漓尽致,能把这些装饰融合到一块,这些五花八门的装饰随机组合,这得要衍生多少个子类啊!!!!!

           我们一般性地算一下,如果有不同的装饰功能 N 个,那么,如果我们将这N个随机组合,将有:    

          

           也就是说做多可以产生sum 个子类,相信学过排列组合的人知道这是个什么概念,另外有多么庞大的代码重复……
 

案例重构

无论怎样,我们不应该采用上面的形式!

        如果修饰者修饰过后,可以将这个修饰过的结果传给下一个修饰者,这样的话,就不需要定义这个么多的组合类了,只需要定义相应类型的修饰者就可以了。如果有10 个修饰者的话,只需要定义10 个修饰者的类,然后在实现的时候我们根据需求添加到相应的修饰就可以了。

         从上面的三个装饰来看,无非是在原有 sing() 方法的基础上添加一些辅助的修饰功能。

        在上面的继承机制上,sing方法在装饰者定义的时候已经是一个固定功能了。如果可以将这个sing()方法变为动态的,即运行时确定的行为,然后再在修饰的时候加上相应的修饰就可以了。

        一个类要动态绑定某个对象的行为,是持有相应的对象引用,然后在运行时根据这个引用绑定的具体对象,体现出不同的行为,这个就是动态绑定。

        依照上面定义的规则,我们可以通过下面来实现,定义一个Decorator类,持有一个Competitor对象,只有当运行的时候动态绑定到sing() 方法。然后在这个sing() 方法的基础上进行装饰,加入相应的辅助、增强功能。
 

public class CompetitorDecorator extends Competitor{
 
    private Competitor competitor;
 
    public CompetitorDecorator(Competitor competitor)
    {
        this.competitor= competitor;
    }
    public void sing()
    {
        competitor.sing();
    }
}

这样的话,如果我们在创建Decorator对象的时候,如果传入的Competitor 是已经被修饰过的,即sing()方法是被重写过的,那么我们就可以在此基础上再添新的修饰了。

我们重构上面的三个修饰类如下:

1.舞蹈修饰类:

public class CompetitorDecoratorA extends CompetitorDecorator {
    public CompetitorDecoratorA(Competitor competitor) {
        super(competitor);
    }
    public void sing()
    {
        this.dance();
        super.sing();
    }
    private void dance()
    {
        System.out.println("偏偏起舞....");
    }
 
}

2.伴奏修饰类:

public class CompetitorDecoratorB extends CompetitorDecorator {
    public CompetitorDecoratorB(Competitor competitor) {
        super(competitor);
    }
    public void sing()
    {
        this.playMusic();
        super.sing();
    }
    private void playMusic()
    {
        System.out.println("播放背景音乐......");
    }
}
 

3. 身世介绍类:

public class CompetitorDecoratorC extends CompetitorDecorator {
    public CompetitorDecoratorC(Competitor competitor) {
        super(competitor);
    }
    publi cvoid sing()
    {
        super.sing();
        this.introduceBackground();
    }
    private void introduceBackground()
    {
        System.out.println("悲惨背景介绍,博取同情,赢感情牌....");
    }
}

Client 类

public class Client {
 
    public static void main(String[] args) {
 
        Competitor com = new Competitor();
 
        // 加入了跳舞修饰,decorator 的sing() 方法中被动态添加了dance 修饰
 
        CompetitorDecorator decorator = new CompetitorDecoratorA(com);
 
        // 在上面修饰的基础上,加入背景音乐修饰
 
        decorator = new CompetitorDecoratorB(decorator);
 
        // 在上面修饰的基础上,加上悲惨的身世介绍
 
        decorator = new CompetitorDecoratorC(decorator);
 
        decorator.sing();
 
        System.out.println("满场尖叫,满分通过!!!!!");
 
    }
 
}

程序运行结果:

通过这种装饰方式,我们可以很方便地根据具体情况增加修饰者,并且不会产生多余的子类,整个过程很灵活,不像单纯使用类继承的方式会产生很多子类。

装饰者模式目的:

  • 给对象动态地添加附加功能。
  • 装饰者提供了一个灵活的拓展子类功能的备选方案。

  • Component :定义了一个可以被动态添加功能的接口
  • Decorator :持有一个Component对象的引用,并且定义了一个和Component保持一致的接口。
  • ConcreteDecorator :为Component添加功能的角色。

 

转载自:https://blog.youkuaiyun.com/luanlouis

资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 在 Linux 系统中,查找域名或主机名对应的 IP 地址是网络管理中的一项基础且关键任务,对于排查网络故障、调试网络问题以及监控网络服务是否正常运行等场景都非常重要。本文将介绍五种在 Linux 终端查询域名 IP 地址的方法。 首先,dig 命令(全称 Domain Information Groper)是一个功能强大的 DNS 查询工具,能够向 DNS 服务器发送查询请求并获取详细的响应信息。如果需要查询单个域名的 IP 地址,可以使用命令 dig 2daygeek.com +short 。此外,还可以通过编写 bash 脚本,将包含域名的文本文件中的域名逐个读取,然后利用 dig 命令进行查询,从而实现批量查询域名 IP 地址的功能。 其次,host 命令是一个简单易用的 DNS 查询工具,主要用于将域名解析为 IP 地址。要获取某个域名的 IP 地址,直接使用 host 2daygeek.com 即可。如果只想显示 IP 地址部分,可以通过管道结合 grep 和 sed 命令来实现,例如:host 2daygeek.com | grep "has address" | sed s/has address/-/g 。 再者,nslookup 命令也是一种常用的 DNS 查询工具,它支持交互式查询 DNS 信息。通过 nslookup 2daygeek.com 可以查询域名的 IP 地址。若要以非交互式的方式只显示 IP 地址,可以使用命令 nslookup 2daygeek.com | awk /^Address:/ {print $2} 。 另外,fping 命令与传统的 ping 命令不同,它不会直接进行 DNS 查询,而是通过发送 ICMP Echo Request(pi
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值