装饰模式(完全体会了此模式含义)

第三次复习

场景:

通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。

如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,

这就是装饰器模式的目标。

 

要清楚,此模式的场景,是有一个被装饰对象,比如A,不想修改它。

其他装饰后的对象,比如B,C,D,都必须包含A。

本体A,和装饰后的B,C,D,都必须实现装饰功能,也就是接口。

但是B,C,D最好是实现虚类,这样可以规范装饰类必须符合2点,1.必须包含本地,2.实现装饰功能。而接口只能实现第2点。

这个模式,可以形成丰富多彩的类,所以属于结构型模式。

 

作用是这句:动态地扩展其功能,动态说明不能继承,只能组合,继承是静态扩展。

结构是这句:实现接口的自包含的虚类。

 

 

 

第二次分析感受:

看了下第一次分析。基本是把握到了本质。没有什么偏差。

补充下使用场景需求

1.原对象类必须存在,

2.需要动态组合新功能。

所以下面是推导模式的流程:

所以我们最初的考虑会是添加一个接口,再通过继承复写接口功能来扩展功能。

但是这个继承必须是组合形式的继承。因为需要在原功能的基础上扩展。所以还必须包含原对象。但是这样的话接口就没有强制性了(不能强制要求接口的派生类包含原对象)

所以可以用虚类,定义一个原对象成员变量。而虚类和被装饰的类都派生于同一接口(包含我们需要扩展的函数)。就解决了。

 

 

 

第一次分析:

这个模式也是之前没看懂。

需要看懂的话,要给自己提明确需求。之前没看懂就是因为很多书没有告诉你,为什么要放弃简单的方案。估计那些作者也没有深刻体会吧。

如,一个战士有形象展示。需要给个方案,可以灵活的加特效,如加个冰背景,火背景等。

先不要装b,最开始一定会是直接在类里面加方法。 结果,非常ok。如果你也满意,同事,客户都满意,而且以后改动都不大。那么装饰模式可以根本不要学习。估计你一辈子都用不到。

非常特特特殊情况。装饰动作太繁多,改动太频繁。那么才需要装饰模式。

新的要求。不要在类里面修改。把修改踢到类的外面。 那么逼迫自己想方案。

你会尝试很多方案,大多数都是错误的。

这个方案最起码有几点。

1必须输入输出都是原来的对象。不管你用函数,接口。虚类。各种技术都行,开始别confine自己。

2.需要对原来对象的某个方法复写。

3.继承的写法,是不行的,因为需要无穷的类。想想加火的特效。如果是效果是一点一点的加,想想看。要1000个火特效,需要继承1000次。中间再差点其他特效,而且顺序有关。简直无解。

4.基本上会逼迫你走向一个虚类继承被装饰类,并包含一个被装饰类对象。这样就为形成链条做好了准备,因为包含的是被装饰类,那么最初可以放入基础被装饰类,之后又可以把被装饰类的派生类放进去,形成一个装饰类的派生类,而它又可以放入到。。。

当方法复写的时候。调用包含的装饰类对象的方法。 只有这个时候你才明白,哦,这是装饰模式。才会发现,原来装饰模式这么巧妙。

包含被装饰类,并覆盖方法,调用被装饰类的方法,这个是完成了装饰的目的,比较容易推出来。而最后虚类继承被装饰类,是一个神来之笔。巧妙。

装饰模式从某种意义上,也是对组合方式的支持,继承固定性,无法满足。可以想象为最后展示战士的时候,是一个战士经过一个又一个类,这些类,只是把自己包裹了一下,并对某个方法包装了一下。

 

个人觉得,除非是真的体现了装饰功能,意思就是多变,否则可以用继承。

而且你对代码要求高,否则可以把新的装饰功能,放入到类中。

总结,非常巧妙的模式,和工厂方法一样。都非常巧妙,令人惊叹,但是有简单,易用的替代方案。如果不是特别严苛的话,基本不会使用。

 

关键代码:

public abstract class Decorator extends BaseClass//这里是神来之笔
{ public BaseClass mBaseClass;//可以传递BaseClass,又可以之后传递Decorator,完成了链头和链条的衔接。
        public Decorator( BaseClass heightBSolider) 
{
mBaseClass
=heightBSolider;
}
@Override
public String showMe()
{
return BaseClass.showMe();
}
}

 

 

public class Decorator
{
    //假如我想在showme这个效果上,加点其他效果。第一个想到的便是继承。
    //但是如果效果有上10种。而且排列不同,效果不同,那么继承就基本没办法了。
    //想象3种效果。 单是组合就有3×2种可能。那么就要6个派生类了。这还没有无限叠加效果。
    //当然可以用其他简单方法,直接在类里面加方法,这个类里面的addFire。等方法。简直就是简单到令人发指。
    //但是别忘记了设计模式的原则。 对修改关闭。在一个类中加方法来达到扩展这种做法。比格不高。必须把修改踢到类外部。
    //所以才有了装饰模式。
    //使用不是很常见,因为普通青年,并没有 严苛到 对于很少概率的修改,都把代码提升到设计模式的高度。


    //简单又高效的类,对于一个战士,想加什么特效自己动手,但是比格不高(没有对修改关闭)
    public class Soldier
    {
        public String showMe()
        {
            return "...";
        }
        public String addFire(String show)
        {
            return "$"+show+"$";
        }
        public String addWater(String show)
        {
            return "~"+show+"~";
        }
        public String addSword(String show)
        {
            return "-"+show+"-";
        }
    }



    public class HeightBSolider
    {
        public String showMe()
        {
            return "...";
        }
    }

    //装饰模式,本意是装饰,不改变对象
    //所以,1.必须是输入和输出都是原来的对象。
    //其次,2.一般是对某个方法的复写。
    //所以最直观的是继承。但是不灵活,2中变化,排列要4个类。
    //所以整来整去,装饰类必须继承被装饰类,才能同时满足1,2. 2个条件。
    //而且装饰类必须包含一个被装饰类,这样当装饰类复写方法的时候,不是调用基类的方法,而是调用成员变量的方法。
    //好处在哪里呢?原来固定的多重继承的顺序才能实现的效果,经过包含一个变量,并使用变量的方法来复写。由固定变成了灵活的组合。
    //最终1.装饰类必须继承被装饰类2.构造函数需要传递一个被装饰类,并设置为成员变量。3复写某个需要装饰的方法时,调用类型是被装饰类,而且是自己的成员变量的的方法,
    //来代替基类。
    public class AddFire extends HeightBSolider
    {
        @Override
        public String showMe()
        {
            return "$"+super.showMe()+"$";
        }
    }

    public class AddFirePlus extends HeightBSolider
    {
        @Override
        public String showMe()
        {
            return "$"+super.showMe()+"$";
        }
    }

    public abstract class ABSDecorator extends HeightBSolider
    {
        public HeightBSolider mHeightBSolider;
        public ABSDecorator(HeightBSolider heightBSolider)
        {
            mHeightBSolider=heightBSolider;
        }
        @Override
        public String showMe()
        {
            return mHeightBSolider.showMe();
        }
    }

    public class buff_fire extends ABSDecorator
    {
        public buff_fire(HeightBSolider heightBSolider)
        {
            super(heightBSolider);
        }

        public String showMe()
        {
            return "$"+mHeightBSolider.showMe()+"$";
        }
    }

    public class buff_Water extends ABSDecorator
    {
        public buff_Water(HeightBSolider heightBSolider)
        {
            super(heightBSolider);
        }

        public String showMe()
        {
            return "~"+mHeightBSolider.showMe()+"~";
        }
    }


    public void Run()
    {
//        Soldier LeeDragen=new Soldier();
//        String show=LeeDragen.showMe();
//        show=LeeDragen.addFire(show);
//        show=LeeDragen.addWater(show);
//        LSComponentsHelper.LS_Log.Log_INFO(show);

        HeightBSolider Lee=new HeightBSolider();
        Lee=new buff_fire(Lee);
        Lee=new buff_Water(Lee);
        Lee=new buff_Water(Lee);
        Lee=new buff_Water(Lee);

        LSComponentsHelper.LS_Log.Log_INFO( Lee.showMe());

    }
}

 

posted @ 2019-07-05 09:28  琴鸟  阅读(178)  评论(0编辑  收藏  举报