DECORATOR模式--《敏捷软件开发》读书笔记(二)

比如现在我们有如下的几个类:

class CGShape
{
public :
~ CGShape();
virtual void Draw() = 0 ;
};

class CGRectangle: public CGShape
{
public :
void Draw();
};

class CGSquare: public CGShape
{
public :
void Draw();
};

class CGCircle: public CGShape
{
public :
void Draw();
};

如果现在有些代码的用户有一个特殊的需要,就是要在绘制出图形的时候同时把图形的中心点也绘制出来,那我们该怎么办呢?
很显然,不能直接给各个类的Draw方法中加上绘制中心点的代码,因为并不是所有的用户都需要这个功能。
那么我们可以给基类CGShape增添一个bool类型的成员变量m_bDrawCenter,并添加一个设置该变量值的公有方法SetDrawCenter,再在各个子类的Draw方法里面根据变量m_bDrawCenter的值来判断是否绘制中心点。需要绘制中心点的用户在调用Draw方法之前先调用SetDrawCenter方法把m_bDrawCenter设置为true。
还有一个方法,就是分别以类CGRectangle、CGSquare和CGCircle为基类继承,在各个子类中重载Draw方法,在该方法里面添加绘制中心点的代码。
上面两种方法都可行,可是我们来仔细分析一下这两种方法的缺陷:
方法一,每个类中的Draw方法中都要添加判断变量m_bDrawCenter的值的代码和绘制中心点的代码,这些代码在每个类中都是重复的,添加的工作也是非常枯燥无味。如果说类很多的话,那么做这个工作的程序员会崩溃的。最重要的一点是,如果上面那些类都是包含在库文件中,没有源代码,那么这个方法就根本行不通。
方法二,看起来似乎很符合面向对象设计(OOD),也不需要上面那些类的源代码。但是,这样会产生大量子类,并增加了类的层次结构。而且继承下来的每个子类也都是修改Draw方法,而且添加的绘制中心点的代码也都是重复的。
为了避免上面所说的各种缺陷,我们可以使用DECORATOR模式。看下面这个类:

class CGDrawShapeWithCenter: public CGShape
{
public :
CGDrawShapeWithCenter(CGShape
* pShape);
void Draw();

private :
CGShape
* m_pShape;
};

CGDrawShapeWithCenter::CGDrawShapeWithCenter(CGShape
* pShape)
{
// 得到指向具体图形的指针
m_pShape = pShape;
}

void CGDrawShapeWithCenter::Draw()
{
m_pShape
-> Draw();
// 在这里添加绘制中心点的代码
}

这个类使用起来非常简单,下面这个函数就是绘制一个圆以及圆心:

void DrawCircleWithCenter()
{
CGCirclec
ircle ;
CGDrawShapeWithCentershape(&circle);
shape.Draw();
}

在类CGDrawShapeWithCenter中,我们通过一个指向CGShape的指针获得了要绘制的图形的控制权,用户在调用Draw方法时并没有觉得有什么不同。我们在即不会修改任何类,也不会产生大量子类,更不会有大量重复代码的情况下,满足了特殊用户的需求。
当然我上面举的这个例子非常简单,但是足以说明DECORATOR模式的优点。需要注意的一点就是,类CGDrawShapeWithCenter必须实现所有类CGShape的接口,在不需要修改的接口实现中只要调用指向CGShape的指针m_pShape相应的方法就行了。
现在,有人也许会问:为什么类CGDrawShapeWithCenter要从类CGShape继承?从上面的代码上来看,单独写一个类CGDrawShapeWithCenter也可以实现所有的功能。但是,请看下面这个函数:

void DrawShape(CGShape * pShape)
{
pShape
-> Draw();
}

这个函数是用户写来绘制图形的。如果类CGDrawShapeWithCenter不是从类CGShape继承,那么要在绘制图形的同时把图形的中心也绘制出来,就必须修改这个函数:

void DrawShape(CGDrawShapeWithCenter * pShape)
{
pShape
-> Draw();
}

而如果类CGDrawShapeWithCenter是从类CGShape继承来的,用户就不用修改上面的函数。因为利用类的多态性,把一个类CGDrawShapeWithCenter对象的指针传给函数就行了。比如下面这样:

CGCirclecircle;
CGDrawShapeWithCentershape(
& circle);
DrawShape(
& shape);

也就是说,所有用CGShape的地方都能用CGDrawShapeWithCenter,从而发挥C++类的多态性的强大功能。在这种情况下,用户代码的修改量也可以降到最小。而这样做最大的好处是decorator类CGDrawShapeWithCenter还能被其他decorator类来修饰。其实,DECORATOR模式最精妙的地方就是decorator类是从要修饰的类的基类继承,而且有一个指向被修饰类的指针的成员。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`vue-property-decorator` 是一个用于在 Vue 中使用装饰器语法的库,它提供了一些装饰器来简化 Vue 组件的开发过程。这些装饰器可以用于定义组件的属性、方法、计算属性、生命周期钩子等。 以下是一些常用的装饰器和它们的用法: - `@Component(options?: ComponentOptions)`:将一个类声明为一个 Vue 组件。可以传入一个可选的 `ComponentOptions` 对象来配置组件选项,例如 `template`、`props`、`computed` 等。 - `@Prop(options?: (Vue.PropOptions | Vue.Constructor[] | Vue.Constructor)[] | Vue.PropOptions)`:定义一个组件的 prop 属性。可以传入一个可选的 `PropOptions` 对象来配置 prop 的类型、默认值等。 - `@Watch(path: string, options?: WatchOptions)`:监听一个属性或表达式的变化,并在变化时执行相应的方法。可以传入一个可选的 `WatchOptions` 对象来配置监听选项,例如 `deep`、`immediate` 等。 - `@Emit(event?: string)`:将一个方法标记为触发事件的方法,并指定要触发的事件名。可以传入一个可选的事件名,默认为方法名。 - `@Ref(refKey?: string)`:获取子组件或 DOM 元素的引用,并将其赋值给指定的属性。可以传入一个可选的引用键,默认为属性名。 - `@Inject(key?: string | symbol)`:注入一个父组件提供的属性或方法。可以传入一个可选的注入键,默认为属性名。 - `@Provide(key?: string | symbol)`:在组件中提供属性或方法,以供子组件注入使用。可以传入一个可选的提供键,默认为属性名。 - `@Model(event?: string, options?: (PropOptions | Constructor[] | Constructor)[] | PropOptions)`:将一个 prop 属性设置为组件的 v-model。可以指定要触发的事件名和 prop 的配置选项。 这些装饰器可以与 `vue-class-component` 一起使用,帮助我们更清晰、简洁地定义 Vue 组件,并提供更好的类型支持和可读性。 希望这些笔记对你有所帮助!如有任何疑问,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值