美文网首页
大话设计模式之装饰模式

大话设计模式之装饰模式

作者: 大炮对着虫子 | 来源:发表于2018-08-09 15:16 被阅读5次
    装饰模式

    装饰模式(Decorator)动态的给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活。将类中的装饰功能从类中搬移去除,这样简化了原有的类。

    引子

    做一个人可以搭配不同服装的系统。
    版本一:

    package decorator;
    
    public class Person1 {
        private String name;
        public Person1(String name)
        {
            this.name=name;
        }
        public void WearBigTrouser()
        {
            System.out.println(this.name+"穿垮裤");
        }
        public void WearSneakers()
        {
            System.out.println(this.name+"破球鞋");
        }
        public void WearSuit()
        {
            System.out.println(this.name+"穿西装");
        }
        public void WearLeatherShoes()
        {
            System.out.println(this.name+"穿皮鞋");
        }
        public static void main(String[] args) {
            Person1 p1=new Person1("菜菜");
            p1.WearBigTrouser();
            p1.WearLeatherShoes();
        }
    }
    

    如果按照这种写法,当我们需要增加一件装扮的时候,就需要去改动Person1这个类,这就违背了 开放-封闭原则,衣服这种需求是会经常变化的,对于这种可能存在变化的功能,我们一般会将它抽象出来,利用继承、多态,使其满足多变的需求。

    抽象 皮肤类

    package decorator;
    
    public interface Skin {
        public abstract void  MyShow();
    }
    
    

    头盔皮肤

    package decorator;
    
    public class HeadSkin implements Skin{
    
        @Override
        public void MyShow() {
            // TODO Auto-generated method stub
            System.out.println("鸡冠头");
        }
    
    }
    

    全身皮肤

    package decorator;
    
    public class ClothesSkin implements Skin {
    
        @Override
        public void MyShow() {
            // TODO Auto-generated method stub
            System.out.println("金光闪闪的全身");
        }
    
    }
    

    客户端代码:

    package decorator;
    
    public class Person2 {
        public String name;
        public Person2(String name)
        {
            this.name=name;
        }
        public void MyClothes()
        {
            System.out.println("这就是我的新衣");
        }
        public static void main(String[] args) {
            Skin s=new HeadSkin();
            s.MyShow();
            Skin s2=new ClothesSkin();
            s2.MyShow();
            Person2 p2=new Person2("菜");
            p2.MyClothes();
            
        }
    }
    
    

    结果:

    鸡冠头
    金光闪闪的全身
    这就是我的新衣
    

    这个时候,如果我们需要增加裤子或者换其他款式的衣服,我们并不需要去修改,暴露原来已经写好的其他衣服的设计的代码,只需 增加一个 Skin的子类 即可。
    仔细观察上面代码,会发现一个问题,人和衣服是分开的,感觉就像是 ‘鸡冠头’,‘金光闪闪的全身’,‘这就是我的新衣’ ,这三件 一个一个拼接显示出来, 这样子显然不妥,我们期望的是 能够在 内部组装完毕,然后再显示出来,穿衣,衣服的先后顺序不同,搭配出来的样子也是不同的,所以先后顺序也是有讲究的,我们需要把所需的功能按正确的顺序串联起来进行控制,这就需要我们来学习一个模式--装饰模式

    装饰模式

    装饰模式 动态的给一个对象添加一些额外的职责,从增加功能来说,装饰模式比生成子类更加灵活。

    例子: 不同的身份可能会搭配不同的服装,人的身份,服装都是会改变的。

    person类,作为基类,有姓名的属性 和消费的 功能

    package decorator;
    
    public abstract class Person {
        protected String name;
        
        public void SetName(String name)
        {
            this.name=name;
        }
        public String GetName()
        {
            return this.name;
        }
        public  String getDescription()
        {
            return this.name+"买了:";
        }
        public   abstract double cost();
        
    }
    

    人的身份是不同且多变的,有医生,程序员,还有法师,还有战斗法师等等
    青少年 类:

    package decorator;
    
    public class Teenager extends Person{
    
        public Teenager(String name)
        {
            this.name=name;
        }
        @Override
        public double cost() {
            // TODO Auto-generated method stub
            return 0;
        }
    
    }
    
    

    年轻少女 类

    package decorator;
    
    public class YoungLady extends Person{
    
        public YoungLady(String name)
        {
            this.name=name;
        }
        @Override
        public double cost() {
            // TODO Auto-generated method stub
            return 0;
        }
    
    }
    
    

    服装 作为装饰类 Decorator,而且不同的衣服多种多样

    package decorator;
    
    public abstract  class ClothingDecorator extends Person  {
         public abstract String getDescription();
    }
    
    
      package decorator;
    public abstract class HatDecorator extends Person{
        public abstract String getDescription();
    }
    
    package decorator;
    
    public class Shirt extends ClothingDecorator{
    
        Person person;
        public Shirt(Person person)
        {
            this.person=person;
        }
        @Override
        public String getDescription() {
            // TODO Auto-generated method stub
            return person.getDescription()+"a shirt ";
        }
    
        @Override
        public double cost() {
            // TODO Auto-generated method stub
            return 100+person.cost();
        }
    
    }
    
    
    package decorator;
    
    public class Hat extends HatDecorator {
    
        Person person;
        public Hat(Person person)
        {
            this.person=person;
        }
        @Override
        public String getDescription() {
            // TODO Auto-generated method stub
            return person.getDescription()+"a Hat ";
        }
    
        @Override
        public double cost() {
            // TODO Auto-generated method stub
            return 50+person.cost();
        }
    
    }
    
    

    客户端代码:

      package decorator;
    
    public class Person3 {
        
        public static void main(String[] args) {
            Person p1=new Teenager("年轻菜");
            p1=new Shirt(p1);
            p1=new Hat(p1);
            System.out.println(p1.getDescription()+p1.cost());
            
            Person p2=new YoungLady("女仔");
            p2=new Shirt(p2);
            p2=new Hat(p2);
            System.out.println(p2.getDescription()+p2.cost());
        }
        
    }
    
    

    结果:

      年轻菜买了:a shirt a Hat 150.0
    女仔买了:a shirt a Hat 150.0
    
    

    UML类图

    image.png

    1、Component是基类。在上面的例子中,person类则是基类。通常是一个抽象类或者一个接口,定义了属性或者方法,方法的实现可以由子类实现或者自己实现。通常不会直接使用该类,而是通过继承该类来实现特定的功能,它约束了整个继承树的行为。比如说,如果Component代表人,即使通过装饰也不会使人变成别的动物。
    2、ConcreteComponent是Component的子类,实现了相应的方法,它充当了“被装饰者”的角色。 在上面例子中,YoungLady和Teenager 为‘被装饰者’
    3、 Decorator也是Component的子类,它是装饰者共同实现的抽象类(也可以是接口)。比如说,Decorator代表衣服这一类装饰者,那么它的子类应该是T恤、裙子这样的具体的装饰者。 在上面例子中,ClothingDecorator和HatDecorator 则为Decorator
    4、ConcreteDecorator是Decorator的子类,是具体的装饰者,由于它同时也是Component的子类,因此它能方便地拓展Component的状态(比如添加新的方法)。每个装饰者都应该有一个实例变量用以保存某个Component的引用,这也是利用了组合的特性。在持有Component的引用后,由于其自身也是Component的子类,那么,相当于ConcreteDecorator包裹了Component,不但有Component的特性,同时自身也可以有别的特性,也就是所谓的装饰。上面例子中,Shirt和Hat 则为ConcreteDecorator

    应用

    学习了装饰者模式用法、特点以及优缺点后,我们再来看看装饰者模式在实际开发过程的应用。装饰者模式在Java中经常出现的地方就是JavaIO。提到JavaIO,脑海中就冒出了大量的类:InputStream、FileInputStream、BufferedInputStream……等,真是头都大了,其实,这里面大部分都是装饰类,只要弄清楚这一点就容易理解了。我们来看看JavaIO是怎样使用装饰者模式的。
    从字符流来分析,我们知道,有两个基类,分别是InputStreamOutputStream,它们也就是我们上面所述的Component基类。接着,它有如下子类:FileInputStreamStringBufferInputStream等,它们就代表了上面所述的ConcreteComponent,即装饰对象。此外,InputStream还有FilterInputStream这个子类,它就是一个抽象装饰者,即Decorator,那么它的子类:BufferedInputStreamDataInputStream等就是具体的装饰者了。那么,从装饰者模式的角度来看JavaIO,是不是更加容易理解了呢?

    相关文章

      网友评论

          本文标题:大话设计模式之装饰模式

          本文链接:https://www.haomeiwen.com/subject/wczevftx.html