UML 重用,粒度,模式和稳健性的常见错误以及如何纠正它们

重用,粒度,模式和稳健性的常见错误以及如何纠正它们

 

 

重复使用,粒度,模式和稳健性的常见错误以及如何纠正它们

常见错误

纠正错误

举例

只考虑“有”重用而不是“重用”

制定策略以开发可重用的类以供将来使用; 确保人们理解“for”重用需要额外的贡献,并且管理层准备承认对未来利益的贡献。

请参见图15.1,其中显示了重用的两个方面。

创建随机大小的类

检查项目的粒度需求,并确保解决方案空间中的类的平衡大小。

重新阅读图15.3及其周围的讨论,以了解实践中的粒度。

不将设计重用与运行时重用分开

设计重用侧重于使用继承的类的结构; 运行时重用基于对已经实例化的服务的“调用”。

有关不同类型重用的示例,请参见图15.1; 然后考虑设计和运行时重用之间的区别。

将设计模式视为实施模式

设计模式正是抽象的思维过程。 它们需要转换为针对特定现实情况的实现。

参见图15.4和15.5作为实现设计模式的实际示例。

在稳健性方面走向“极端”

并非每个实际设计都遵循稳健性 - 主要是因为这种稳健性会在运行时增加大量开销。

重新访问图15.9,了解在实践中如何应用健壮性。

忽略创建系统架构和设计的过程和步骤

遵循系统架构和设计的过程有助于重用和质量。

例如,通过利用在前一次迭代/项目中开发的“重用”类来“重用”设计类。

不分离架构的功能和技术方面

系统架构的功能和技术层相互交叉。 功能层表示系统的行为,而技术层表示数据库,规则和接口。

重新阅读图15.10,以进一步了解系统的功能层和技术层之间的差异。 使用该信息创建基本系统体系结构。

 

 

 

 

鲁棒是Robust的音译,也就是健壮和强壮的意思。 它是在异常和危险情况下系统生存的关键。 比如说,计算机软件在输入错误、磁盘故障、网络过载或有意攻击情况下,能否不死机、不崩溃,就是该软件的鲁棒性。 所谓“鲁棒性”,是指控制系统在一定(结构,大小)的参数摄动下,维持其它某些性能的特性。

 

学习目标

◾了解软件可重用性的各种级别,类型和方法

◾了解类设计粒度对系统的可重用性和可维护性的影响

◾应用设计模式以提高类图的质量

◾在面向对象设计中应用鲁棒性概念,以提高系统的可维护性

◾了解基本系统架构(特定于软件)并将其与封装图相关联简介

 

本章讨论软件工程中的一些高级概念,这些概念在解决方案和架构建模空间(MOSS,MOAS)中具有特殊价值。这些高级概念基于早期对类和序列图的讨论。

本讨论的重点是创建一个健壮,可重用且高质量的软件设计。这种高质量的设计对于当前项目之外的组织具有价值。本章的讨论包括可重用性,理解“with”和“for”重用,面向对象设计中的粒度以及应用设计模式。还提到了支持质量设计的开发过程的相关方面。

 

软件工程中的可重用性

可重用性被认为是面向对象(OO)对软件工程领域的主要贡献。这是因为OO为软件开发人员提供了第一次在新类中再次使用现有类而无需修改的机会。

重复使用可提高生产率和提高输出质量。

重用级别 了解软件开发中的各种重用级别是提高可重用性的良好起点。

 

图15.1显示了软件工程中普遍存在的三种不同重用级别:

 

◾代码级重用 - 当新类基于现有的完全编码类时发生。

 

◾设计级重用 - 当所有新设计的基础都基于现有设计和可用设计模式时,就会发生。

 

◾分析级别重用 - 可以跨多个项目在组织级别进行。在一个项目中确定的要求可以在另一个项目中重复使用(通过适当的修改)。这种分析级别的重用需要组织范围的重用文化。

 

1.代码级重用

当类重用另一个类时,会发生代码级重用。这意味着继承的类使用基类的任何函数(或属性)。代码级重用还包括在实现语言和开发环境中重用类。

图15.1a显示了左侧的这种基本重用。代码示例显示了如何创建继承Person类的新Patient类。患者可以使用Person的所有属性和关系,而无需在Person类中再次显式声明。代码级重用取决于程序员对开发环境的了解以及现有类的可用性。

 

2.设计级重用

设计级别的重用基于类设计,组件,框架,包和服务。在这个级别重用很重要,因为它发生在比代码级重用更高的级别,因此对项目有更大的影响。例如,与重用类相比,重用整个可执行库或调用复杂的分析服务对开发的影响要大得多。这是在设计或“模式级别”的重用,为软件项目提供了主要的好处。这是项目中的重用,也可以跨多个项目提供价值。

图15.1b显示了第二种重用形式,其中可以基于现有设计或模式对类及其关系进行建模。图15.1显示了基于Gamma(Gamma等人1995)观察者模式的设计(本章后面将讨论)。主体和患者之间的继承不是基于类背后的语义含义,而是基于它们的实现特征。来自相应的Subject和Observer类的Patient和Doctor类的继承有助于实现Observer模式,而系统设计者只需要很少的努力。图15.1b显示了如何根据实现中的设计特性重用整个类集。

 

3.分析级重用

第三种重用形式位于分析级别,如图15.1c右侧所示。在此级别,需求被记录并从UML提供的用例中重用。用例 - 用例 - 关系有助于这种重用。两个用例之间的<< include >>关系可以在分析级别重用需求。例如,其中一个用例MaintainsCalendar需要检查日历详细信息。与此同时,“预约”和“重新安排咨询”等其他模块也需要查看日历。在这种情况下,开发了一个新的用例ChecksCalendar。稍后,需要使用此用例的其他用例可以包含它用于实现。这种重用如图15.1所示,其中MaintainsCalendar用例包括ChecksCalendar用例。

 

软件项目中的重用策略

重用策略在软件项目中提供比代码级重用更大的价值。需要仔细考虑这些重用策略,并得到所有利益相关方的同意,并将其纳入软件开发过程。战略性重用可为项目和组织带来生产力和质量收益。

 

重用可提高工作效率,因为重用的类和组件不是从头开始设计的。还不需要再次测试重用的类和组件(除了具有继承类的新接口)。因此,基于现有类的类减少了编码以及测试工作量,从而提高了质量并提高了生产率。然而,这种重用需要一种超越一个项目并进入组织内所有项目的战略方法。

封装有助于重用除了继承之外,封装还有助于OO的可重用性,从而提高生产力和质量。正如第1章中的OO基础知识所讨论的,封装通过其函数或方法“包装”类属性。由于数据和函数在一个类中被“封装”在一起,因此可以很容易地将逻辑和执行中的潜在错误精确定位到特定类。 OO中的错误的缩小在程序设计中不容易发生,因为错误可能发生并且流经系统的任​​何部分而不被本地化。

 

对于面向对象的设计,如果对象在检索某些属性的值时“抛出”错误,则该错误相对容易地追溯到该特定对象及其相应类的代码。此外,由于封装,错误仍然存​​在于类中,并且不会渗透到系统的其余部分。

 

前面的讨论表明,一旦一个类被设计,开发,测试并放置在一个模块(或一个组件或服务)中,那么该模块就可以被广泛地分发和重用。这种模块的重复使用需要最少的努力,仅限于为新设计的类测试新接口。

 

重用的类具有比新编写的类更高的质量特性,特别是如果它之前已经被重用。这是因为随着类的重用,它们也会在现实生活中通过重用进行测试。因此,一个类被重用的越多,其质量就越高。

为了使封装成功,它必须是项目中设计标准的一部分,因此是项目文化的一部分(如下所述)。应注意确保封装不会退化为数据隐藏的练习。简单地将数据或属性隐藏在函数后面并不能提供与封装相同的质量优势。

举一个简单的例子,考虑HMS中的Patient类和该类中的MedicareNumber属性。如果使用getMedNo()方法访问MedicareNumber,那么实现的是数据隐藏 - 通过函数隐藏数据。如果提供了一个具有业务逻辑的函数(例如getCoverDetails(),而不是getMedNo(),其中包含Medicare编号以及其他字段,则整个业务功能将封装在类中。

作为文化重用项目中的重用文化需要项目管理的战略方法。在组织层面理解重用的一个有用概念如图15.2所示。该图显示了重用的两个“类型”:

1。优化类或组件以供将来重用,从而使项目成为可重用元素的“生产者”;

2.将可重用的类和组件合并到下一个项目中,或“消耗”它们。

前者需要类的泛化,可以称为“for”重用,而后者称为“with”重用。图15.2显示了跨多个项目的这两种类型重用的战略方面。项目1显示为生成可重用组件,项目2正在消耗或“重用”它们。

 

*或类别,将这种重用分组与图15.1中关于重用级别的早期讨论分开。

重用中的泛化与专业化在项目1上工作的建模者和开发人员正在为生成可重用组件做出额外贡献(对他们的正常工作)。这是“为了”未来的重用。这样的重用工作使得从事项目2工作的建模人员和开发人员受益。项目2人员正在“重用”他们的建模工作,因此他们依赖于项目1工作人员所做的工作。

“for”重用的一个例子是Animal类到Living类的泛化。这样的设计具有足够的功能,不仅满足当前项目的需求,而且满足未来项目的需求。第一个“生产者”项目需要额外的努力,特别是在质量保证,质量控制或测试方面。这是因为必须对类进行指定,记录和测试,不仅要为其现在的应用程序,还要为未知的未来使用。

当“重复”发生时,质量区域所需的相对较少的努力抵消了这种额外的努力,因为期望组件的所有基本特征的质量得到保证,并且需要针对由于它们的使用而发生的变化进行重新测试。例如,以Animal为模型的新类Cat是专业化的示例(“有”重用)。在这里,Cat享有动物和生活类开发人员所有设计和测试工作的优势。

面向对象设计中的粒度随着开发的进行以满足当前项目的要求,“for”和“with”重用注意事项明确地影响未来或并发项目的需求。平均等级的大小与项目团队成功创建这种“前馈”机制的能力有关。类的大小是本节中讨论粒度的基础。

粒度意味着,对于给定的功能,可以使用几个大类(粗粒度设计)或大量较小的类(细粒度设计)来创建设计。

图15.2“With”和“for”重用 - 重用策略的一部分。

粒度的概念进一步说明了对象的平均大小

 

“永恒的建筑方式”(1977)4仍然是模式概念的基本阅读,它已被发展为设计模式,作为Gamma等人的可重用面向对象软件的元素。 (1995年)。根据亚历山大的说法,

“每种模式都描述了一个在我们的环境中反复出现的问题,然后描述了该问题解决方案的核心,以这种方式使解决方案可以使用一百万次,而不用做它以同样的方式两次。

 

“尽管亚历山大在谈论建筑和城镇中的模式,但这一概念在面向对象的设计模式中同样如此。

Coplien(1991)5进一步将模式定义为对正在构建的事物的描述和构建事物的过程,在上下文中解决问题的解决方案以及解决给定设计决策中的力量的问题。此定义有助于发现模式并将其应用于软件工程项目。创建的模型和创建这些模型的过程通过上述定义找到了指导。

模式的结构形式上,模式可以通过

模式的四个基本要素   来描述(Gamma等,1995):

 

◾1.模式名称: 用一两个词来描述设计问题,解决方案和后果。

◾2.问题: 描述何时应用模式。

◾3.解决方案 描述了构成设计的元素,它们之间的关系,责任和协作。

◾4.后果 是应用模式的结果和权衡。

 

在解决方案和架构建模空间中使用模式

 

模式在概念层面形式化可重用性(图15.1b)。经验丰富的设计人员可以识别重复的类层次结构,关联类或访问序列,并将它们组合在一起,使它们可以应用于各种实际设计问题。

正如Gamma等人。 (1995)说:“这些模式解决了特定的设计问题,使面向对象的设计更加灵活,优雅,最终可重复使用。”因为它们不仅捕获系统部分,还捕获它们之间的丰富关系(Coplien,1991)5,模式描述了比任何对象或类层次结构更广泛的系统体系结构。

一旦在目录中进行描述和记录,设计模式就成为熟练的源泉,只有经验才能提供 - 通过高效灵活的设计促进重用。模式还解决了对象大小和数量问题 - 帮助决定应该是什么对象。

例如,Gamma等。描述Facade模式,它表示完整的子系统作为对象,以及Flyweight模式,它描述了如何以最精细的粒度支持大量的对象。

因此,可以看出,通过捕获和记录专家明显的重复行为,模式为面向对象的软件工程提供了可重用性和质量。

特别地,设计模式主要在解空间(MOSS)中提供上述值。然而,与分析和架构模式一起,在架构空间(MOAS)中最大化重用和质量的价值。这是因为基于约束和参数在架构空间中做出的组织级决策。

 

粒度的概念进一步指出,面向对象系统中对象/类的平均大小是成功重用设计中的重要考虑因素。

在图15.3中演示了这种粒度概念,其中示出了能够由4个粗粒度类或16个细粒度类实现的相同功能(大致由用例图表示)。

细粒度类需要更多的努力来生成,但它们更可重用。这是因为大量较小的类比新的(粗)类更适合新的场景/需求。这种情况的另一面是更精细的粒度设计需要额外注意质量,因为有更多的类用于给定的功能。此外,不仅是本身,还有需要测试的关系。无论情况如何(精细或粗略),系统架构师和系统设计人员必须牢记创建面向对象设计时的这一重要概念。

软件设计工程中的设计模式什么是模式?

模式是在抽象中捕获的反复出现的“思维过程”。这些“更高级别”的抽象可以在较新的设计中重复使用,而设计师不必经历与从头开始的相同严格。

设计模式提供了重用软件和设计的最流行方法之一,尤其是在面向对象的环境中。由于设计模式的普及,软件工程领域也出现了其他价值模式。这些是:

◾分析模式,描述和模拟问题空间1中的重复现象

◾如前所述,设计模式是解空间中的重复现象(Gamma等,1995)

◾架构模式,是作为正在开发的系统的组织约束而出现的反复出现的现象

◾游戏模式,是软件项目中反复发生的社会心理现象(Unhelkar,2003,2005)2,3更大的粒度设计=粗粒度设计粗粒度系统设计细粒度系统设计更小的粒度=细粒度设计粒度概念有助于表达具有不同“大小”设计的“相同”功能'A10-Account Executive''A20-Client'AddClientsDetails << business >> ChangesClientsDetails << business >>图15.3面向对象设计中粒度的概念。

 

 

 

图15.4演示了在软件架构和设计中使用模式。观察者模式已由Gamma等人详细描述。他们在设计模式方面的热门工作。在该模式中,它们捕获了一个类(Observer)依赖于另一个类(Subject)的情况的本质。主体状态的任何变化都会影响观察者。

表示Observer和Subject的抽象类专门用于concreteObserver和concreteSubject。

从设计角度考虑,需要以某种图形方式(如图形或饼图)表示Excel数据。在这种情况下,Excel工作表中的实际数据是主题,图形是观察者。就类而言,这可以解释如下。考虑对象B的状态取决于对象A的状态。每当对象A的状态改变时,对象B必须重新计算其状态以保持一致。

在HMS域中,此模式可以解释为如图15.4所示。在该图中,concreteObserver由Doctor替换,而concreteSubject由Patient类替换。此设计表明,只要患者的任何细节发生变化,医生就会受到影响。患者状态的变化(例如,InTreatment患者)会影响医院治疗患者的方式。

 

如图15.4所示,这种设计优于从头开发的设计,因为基于观察者模式的设计,Gamma等人的知识和经验。正在被重用。毋庸置疑,这种设计经过进一步修改和扩展,以满足医院领域的完整实施需求,但它肯定比从头开始考虑患者 - 医生协会更好的开始 - 从而提高质量。

attach(Observer)detach(Observer)notify() - doctorState update()update() - patientState getPatientState()* observers subject将Patient的状态返回给任何调用对象,例如Doctor doctorState = policy-> getPatientState()for all o在观察者中{o-> update()}患者医生主题观察者图15.4在HMS中使用设计模式(基于Gamma等人的观察者模式工作)。

通常,在系统中只需要创建一个对象实例,然后由整个系统访问。在这种情况下,需要控制这种单个对象的实例化和访问。这些对象的示例包括通信,数据库访问,窗口管理器和打印缓冲器。系统中全局需要这些对象。拥有此类的多个实例会导致系统不一致。

Singleton模式有助于设计创建,其中基于该模式的类只能被实例化一次。因此,Singleton模式导致封装的全局对象,并且可以检查是否只存在一个对象。

 

 

图15.5显示了如何在HMS中使用Singleton模式的示例。此示例显示了HMS中的一个类,该类只需要一个实例。在HMS中,Hospital对象是唯一的,因为在执行系统时只需要它的一个实例。这是通过基于Singleton模式实现的。如果没有这样的模式,医院实例化的系统部分必须由设计人员和开发人员“手动编码”以确保单一实例化。

设计中的稳健性设计中的稳健性设计中的稳健性是一种探索类之间依赖关系的概念。类之间的这种依赖性或耦合程度是软件工程的传统挑战之一。

如果一个类严重依赖于另一个类,那么一个类中的更改自然会影响依赖于该类的所有其他类。因此,一个类中的更改可以影响其他类,使得几乎不可能在不影响许多其他部分的情况下更改系统的一部分。

简单地说,系统中类之间的依赖性越高,系统的鲁棒性就越低。相反,如果类较少依赖于彼此,那么一个类中的更改对系统中的其他类的影响较小。结果,该系统被认为是健壮的。因此,鲁棒性是一种设计方法,可确保解决方案的一部分能够在不影响系统其他部分的情况下进行更改。

 

 

识别缺乏稳健性考虑图15.6。

 

 

请注意,两个<< entity >>类,Patient和Schedule紧密耦合。即使这些类与<< boundary >>类Patient _ Form相关联,整个设计也是紧密耦合的。一个类(以及运行时的相应对象)的更改会直接影响其他类。

Hospital uniqueInstance ... instance()... return uniqueInstance图15.5 Singleton模式(HMS中的另一个例子,基于Gamma等人的工作)。

 

◾具有UML鲁棒性规则的软件工程鲁棒性是一种特定的设计构造,其中控制器(或管理器)类插入实体,边界和数据库类之间。例如,Patient类可能不直接与Doctor类关联,或者更具体地,Patient类可能不会调用或创建Doctor类,反之亦然。相反,在上述两个类之间引入了一个对象管理器(或具有任何其他名称的类,即<< manager >>或<< controller >>构造型)。此对象管理器负责创建和管理活动对象列表。

这里讨论的鲁棒性概念源于早期的,众所周知的称为MVC *的SmallTalk模式,或模型视图控制器模式。在MVC中,模型(或基于UML的设计中的<< entity >>构造型)和视图(或<< boundary >>构造型)由控制器(或<< controller >>构造型)分隔。

 

在应用稳健性时,设计中包含以下规则(如图15.7所示):

◾边界(接口)类不能相互通信(关联)

◾实体类不能互相交谈(关联)

◾边界和实体类可以与控制类通信

◾控制类可以互相交谈(关联)注意在实践中,这些健壮性规则也可以扩展到<< table >>和<< entity >>关系;这意味着<< entity >>类,

当需要在相应的<< table >>中存储细节时,不能直接这样做。相反,<< entity >>类经过另一个<< control >>,通常是DatabaseManager类,用于在<< table >>中存储细节。

 

在设计中加入鲁棒性图15.8显示了如何在前面图15.6所示的设计中插入<< control >>类。

该图中的类图显示了ConsultationManager控件类将Patient_Form与Patient类分开。 Patient类也与其他实体类Schedule分开。

* MVC模式。

<< entity >> Patient 0 ... 1 1 0 ... 1 << boundary >> Patient_Form << entity >> Schedule与边界类相关联的实体类直接暗示设计中缺乏鲁棒性图15.6识别缺乏鲁棒性。

图15.8左侧显示的类图,

 

在类的标记上标有刻板印象,在图的右侧用图标重复。图标的使用使图表更具可读性,从而更容易发现稳健性(或缺乏稳健性)。实际上,鲁棒性仅限于创建实体和边界对象;一旦创建了对象,它们可能最终会相互发送和接收消息 - 尽管包含了一个控件类。

 

 

 

图15.9显示了现在通过序列图显示在实践中如何实现稳健性的另一个示例。一旦PatientRegistrationForm收到消息A10-Patient(来自用例视图)边界控制control2实体

 

图15.7健壮性规则。

Patient_Form Patient ConsultationManager

Schedule Schedule << entity >> Patient << entity >>

ConsultationManager << control >> Patient_Form << boundary >>

 

 

 

图15.8在设计中加入鲁棒性。

要更新()Patient的详细信息,它会执行内部validatePatientDtls()。然后它将消息savePatient()发送到TransactionManager,它是<< control >>类(在这种情况下是对象,因为它是一个实例级序列图)。然后,该控制对象将消息传递给另一个名为DatabaseManager的控制对象,该对象又调用Patient对象以获取需要保存在数据库中的Patient的详细信息。收到患者详细信息后,DatabaseManager将它们发送到PatientTable进行保存。

实际上,通过此序列图中的两个控制对象实现的这种稳健性可能会对系统性能产生负面影响。这是因为消息需要通过其他控制器对象。这里的平衡行为是牺牲一小部分性能来获得设计灵活性和稳健性。

 

系统架构和设计过程到目前为止讨论的高级设计概念在架构空间模型(MOAS)的构建中具有重要价值。以下是关于构建这样的系统架构模型的讨论。

像系统设计人员,系统架构师和项目经理之类的项目角色需要整合在一起并进行战略性工作,以实现重用的粒度和稳健性。创建原型(可执行文件)和改进需求等技术支持早期关于重用和质量的讨论。操作考虑因素(系统运行时的要求)也在开发MOAS时发挥作用。以下是与开发良好系统架构相关的活动和任务。

ActorStaff PatientRegistrationForm TransactionManager Patient DatabaseManager PatientTable update()validatePatientDtls()savePatient()控件类确保设计的稳健性savePatientDtls()getPatientDtls()savePatientRecord()

图15.9健壮性对保存患者注册详细信息的过程的影响。

 

 

调查系统(以及组织内的其他系统)的现有架构和设计:

◾了解系统的当前系统架构和设计需求

◾将当前系统体系结构与组织的现有企业体系结构(EA)相关联

◾了解创建问题空间模型(MOPS)中指定的当前操作要求

 

 融合模式

◾认识到当前设计中的“模式”情况

◾确定可在当前设计中使用的合适设计模式

◾尝试使用可用的模式,以查看哪些模式最适合使用

◾在您的设计中加入合适的图案

◾使用选定的模式进行设计演练

 

系统架构创建

◾为系统创建信息体系结构

◾创建数据库体系结构以启用系统的持久性功能

◾执行架构原型(这和下一个任务与原型制作流程组件相关),以便了解架构需求

◾根据架构原型检查当前系统架构

 

 操作要求确认

◾确保性能要求由系统体系结构处理

◾确保系统体系结构处理卷要求

◾确保体系结构具有可扩展性,这将使系统随着系统用户需求的增长而增长

◾确保将系统的安全要求合并到体系结构中。

特别是在Web应用程序中,必须在性能和安全性要求之间取得平衡。图15.10显示了HMS的基本系统体系结构。基于对系统基础结构的理解,该体系结构分为三个部分:用户界面,业务规则和数据库。这三层散布着四个功能层:患者,员工,咨询和账户。

在实践中,可能有更多的功能划分。系统的功能层和基础架构层之间的交叉是创建包的基础。因此,这样的架构图也是在项目的早期绘制的(再次参考第3章中关于创建包的讨论)。

该体系结构的每个横截面都可以是一个包,如图15.10所示。或者,GUI和数据库可以各自放在一个包中,并且功能部分可以放在它们自己的包中。这种划分的基本思想是创建由包表示的可管理子系统。

图15.10显示了HMS的基本系统体系结构。基于对系统基础结构的理解,该体系结构分为三个部分:用户界面,业务规则和数据库。这三层散布着四个功能层:患者,员工,咨询和账户。

在实践中,可能有更多的功能划分。系统的功能层和基础架构层之间的交叉是创建包的基础。因此,这样的架构图也是在项目的早期绘制的(再次参考第3章中关于创建包的讨论)。

该体系结构的每个横截面都可以是一个包,如图15.10所示。或者,GUI和数据库可以各自放在一个包中,并且功能部分可以放在它们自己的包中。这种划分的基本思想是创建由包表示的可管理子系统。

重复使用,粒度,模式和稳健性的常见错误以及如何纠正它们

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值