zoukankan      html  css  js  c++  java
  • 设计模式之装饰器模式

    装饰器模式--导读

      社会在进步,人类的生活方式越来越方便,同时我们对生活的要求越来越高,就像我们用的手机,原先只有打电话和发短信的功能,由于人们的生活质量的提高人们就给手机添加了很多额外的功能。我们应该知道在面向对象中我们为类添加新的功能,要么使用继承,将新加的功能静态的加入到子类中去,但是这样会产生一个问题,当我们又要在新的子类上增加新的功能的时候又要创建一个新的类去继承,这样就导致类与类之间的耦合度太高,而且拓展非常不方便。于是我们就选择领外一种方法,那就是关联,将一个对象嵌入到另一个对象中,由另外那个对象判断是否要将功能添加到其中。这样既不会破坏类的封装性,类与类之间也实现了松耦合,同时也使得系统更好维护。

    装饰者模式--定义

      装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

    这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

    装饰者模式--结构

          

            Component: 抽象构件。是定义一个对象接口,可以给这些对象动态地添加职责。

            ConcreteComponent:具体构件。是定义了一个具体的对象,也可以给这个对象添加一些职责。

            Decorator: 抽象装饰类。是装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,是无需知道Decorator存在的。

            ConcreteDecorator:具体装饰类,起到给Component添加职责的功能。

    装饰者模式--代码实现

      下面我以手机为例来进行实现:

    phone.java

    package Deraction_Pattern;
    
    public interface Phone {
        public  void function();
    }

    MyPhone.java

    package Deraction_Pattern;
    
    public class MyPhone implements Phone {
    
        @Override
        public void function() {
            System.out.println("打电话");
        }
    }

    PhoneDecorator.java

    package Deraction_Pattern;
    /**
     * 为什么装饰类要实现phone的接口,可能你会问
     * 手机在装饰完了之后肯定也还是手机,并不是变成其他
     * 而且在装饰完了之后还可以在原先的基础上继续添加新的功能
     * @author xyxy001
     *
     */
    public abstract class PhoneDecorator implements Phone {
        //定义一个实例变量保持对被装饰者的引用
        Phone phone;
        public PhoneDecorator(Phone phone){
            this.phone=phone;
        }
        protected abstract void addNewFunction();
    }

    两种装饰类:如果想要额外的增加类也可以直接增加

    PlayMusic.java

    package Deraction_Pattern;
    
    public class PlayMusic extends PhoneDecorator{
    
        public PlayMusic(Phone phone) {
            super(phone);
        }
    
        //加完新功能后的功能
        @Override
        public void function() {
            phone.function();
            addNewFunction();
        }
    
        //新加的功能
        protected void addNewFunction() {
            System.out.println("新加的放音乐的功能");
        }
    
    }

    PlayVideo.java

    package Deraction_Pattern;
    
    public class PlayVideo extends PhoneDecorator {
    
        public PlayVideo(Phone phone) {
            super(phone);
            // TODO Auto-generated constructor stub
        }
    
        @Override
        public void function() {
            //保持新加功能前的功能
            phone.function();
            //决定是否添加工能
            addNewFunction();
            
        }
        @Override
        protected void addNewFunction() {
            // TODO Auto-generated method stub
            System.out.println("新加的看视屏的功能");
        }
    
    }

    Client.java

    package Deraction_Pattern;

    public class Client {
        public static void main(String[] args) {
            
            //这是我的手机只有打电话的功能
            MyPhone phone=new MyPhone();
            
            phone.function();
            System.out.println("/**********************/");
            //现在我想让我的手机具有播放音乐的功能
            PlayMusic musicPhone=new PlayMusic(phone);
            //于是我的手机变成了音乐手机
            musicPhone.function();
            
            System.out.println("/**********************/");
            //现在我想让我的手机具有播放视频的功能
            PlayVideo playVideo=new PlayVideo(musicPhone);
            
            //于是我的手机又在原先的基础上添加了播放视频的功能
            
            playVideo.function();
        }
    }

    运行结果:

    装饰者模式--优缺点

    优点:

             1、装饰者模式可以提供比继承更多的灵活性

               2、可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。

               3、通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。

               4、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

    缺点:

            1、会产生很多的小对象,增加了系统的复杂性

                 2、这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

     装饰者模式--适用场景

         1、在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

                     2、需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。  当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

  • 相关阅读:
    LeetCode OJ 107. Binary Tree Level Order Traversal II
    LeetCode OJ 116. Populating Next Right Pointers in Each Node
    LeetCode OJ 108. Convert Sorted Array to Binary Search Tree
    LeetCode OJ 105. Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode OJ 98. Validate Binary Search Tree
    老程序员解Bug的通用套路
    转载 四年努力,梦归阿里,和大家聊聊成长感悟
    转载面试感悟----一名3年工作经验的程序员应该具备的技能
    Web Service和Servlet的区别
    关于spring xml文件中的xmlns,xsi:schemaLocation
  • 原文地址:https://www.cnblogs.com/sank/p/10679837.html
Copyright © 2011-2022 走看看