闲谈开闭原则——基于UI动画框架

15 篇文章 0 订阅
9 篇文章 0 订阅

  本文继续聊另外一个设计原则:开闭原则。在UI动画框架中,开闭原则在“动画策略”和“移动算法”这两个类体系中均有所体现。照旧,先看一下开闭原则的定义。

1. 开闭原则

一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

  有人说过“唯一不变的就是变化”,尤其是软件需求的变化。在不断支持新需求的时候,应尽量避免“修改”已有的代码,尽量通过“扩展”来实现变化。所谓的“修改”,指的是修改现有系统的关键抽象,比如在继承体系中修改类的设计;而“扩展”指的是在现有系统的基础(或框架)之上附加新的组件来实现新增的功能,比如新加入一个派生类,新注册一个回调函数等。

  有人可能会说,新加一个派生类,总要在一个地方创建这个派生类的实例对象吧,这不算是“修改”吗?算!确实是修改了现有代码。但是这个修改只局限在“初始化”阶段(或者说“配置”阶段),而现有系统的核心抽象层并没有感知到这个修改,核心逻辑也不用做任何改动,这就是“对修改关闭”的含义。

2. 框架中的开闭原则

  开闭原则在动画框架中有两处体现,一个是策略类体系:

在这里插入图片描述

在实际应用中,UI动画框架扩展的需求已经多达10个以上,在应用初期,也只有简单的几个动画策略,比如:帧率、移动、缩放等。某一天,客户提了一个“淡入淡出”的动画需求,框架怎么支持呢?步骤大概是这样的:

  1. 首先实现“淡入淡出”的功能类:FadeStrategy;
  2. 接着在初始化阶段,将该类纳入框架;
  3. 最后,客户在配置文件中用动画语言编写具体的动画。

第2步骤涉及到的初始化阶段的改动,在这里:

IStrategy* AnimationParser::BuildStrategy(const AttriMap& attributes) const
{
    if (attributes["id"] == "frame"):
        return new FrameStrategy(attributes["param"]);
    else if (attributes["id"] == "move"):
        return new MoveStrategy(attributes["param"]);
    else if (attributes["id"] == "scale")
        return new ScaleStrategy(attributes["param"]);
    else if (attributes["id"] == "fade")
        return new FadeStrategy(attributes["param"]);
    ...
    else
        throw ("invalid strategy type!") + attributes["id"]);
}

BuildStrategy就是初始化阶段负责将具体策略类加入进框架的地方。我们对现有代码所作的修改仅此而已,框架的核心抽象:Window类、IStrategy基类以及现有的各派生类(FrameStrategy、MoveStrategy或ScaleStrategy)都没有做任何修改,甚至是使用该新增动画策略(FadeStrategy)的地方也没有改动,在框架中,你甚至不知道在哪里使用了这个新增动画策略,一切都隐藏在IStrategy背后。我们为框架新增了功能,但没有对核心做任何修改,我们轻而易举地做到了“对扩展开放,对修改关闭”!

  另外一处体现开闭原则的地方是移动算法类体系:

在这里插入图片描述

窗口移动方式很快就由直线移动(水平、垂直、斜线平移),扩展到二次曲线移动(抛物线、反抛物线移动等)。比如又来了一个圆形转动的需求!实现的步骤如下:

  1. 首先实现“圆形”轨迹的功能类:Circle;
  2. 接着在初始化阶段,将该类纳入框架;
  3. 最后,客户在配置文件中用动画语言编写具体的动画。

第2步骤涉及到的初始化阶段的改动,在这里:

Locus* BuildLocus(const String& type, ...)
{
    if (type == "horizontal")
        return BuildHorizontal(...);
    else if (type == "parabola")
        return BuildParabola(...);
    else if (type = "circle")
        return BuildCircle(...);
    ...
    else
        return nullptr;
}

我们再一次看到了开闭原则的体现。

3. 结语

  有关设计模式的几个原则,比如“依赖倒置”原则、“接口隔离”原则、“最少知识”原则以及本文讨论的“开闭”原则,这些原则有相当程度上的相通性,虽然它们的实现方式各不相同,但它们都有一个共同点:解耦!
  就我个人的理解,还有一个“逻辑与数据分离”的原则(或者说算法与数据分离)基本上也是在为解耦而翻来覆去的捣腾!当你准备对你的业务实施“算法与数据”分离原则的时候,你得到的类图框架大抵是这样的:

在这里插入图片描述

  只有最大限度的解耦,你才有足够的自由度,以足够低的代价修改你的系统,扩展你的框架,支持多变的需求!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值