面向对象设计原则

0.引言

文章是重复造轮子,记笔记给自己看,勿喷。

重新认识面向对象

  • 理解隔离变化
    从宏观层面来看,面向对象的构建方式更能适应软件的变化,能将变化所带来的影响减为最小

  • 各司其职
    • 从微观层面来看,面向对象的方式更强调各个类的“责任”
    • 由于需求变化导致的新增类型不应该影响原来类型的实现—是所谓各负其责

  • 对象是什么?
    • 从语言实现层面来看,对象封装了代码和数据。
    • 从规格层面讲,对象是一系列可被使用的公共接口。
    • 从概念层面讲,对象是某种拥有责任的抽象。

1.设计原则

1.1.依赖倒置原则( DIP)

  • 高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定) 。
  • 抽象(稳定)不应该依赖于实现细节(变化) ,实现细节应该依赖于抽象(稳定)。

(电脑主板案例)模块间的依赖通过抽象发生,实现类之间不直接发生依赖关系,其依赖关系是通过接口或抽象类产生的。针对接口编程(虚基类),不针对实现编程

  • 针对接口编程,而不是针对实现编程。
  • 使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不是使用具体的类
  • 变与不变的分离。共性的部分为父类,变化的部分为子类。

Apollo 代码基本都是这样:

在这里插入图片描述
请添加图片描述

通过基类隔离变化。

1.2.开放封闭原则( OCP)

  • 对扩展开放,对更改封闭。
  • 类模块应该是可扩展的,但是不可修改。

如果新增加一个逻辑功能点,需要增加新的else 或者 else if ,势必修改了已有代码,则破坏了OCP原则

1.3.单一职责原则( SRP)

  • 一个类应该仅有一个引起它变化的原因。
  • 变化的方向隐含着类的责任

1.4.Liskov 替换原则( LSP)

  • 子类必须能够替换它们的基类(IS-A)。
  • 继承表达类型抽象。

如果一个程序P(T1) ,如果将输入T1 替换为T2 ,而且 P(T1) = P(T2),那么T2 是T1的子类型。

  • 简单的概述就是 : 所有引用基类的地方必须能透明地使用其子类的对象。
  • 里氏代换原则的根本,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常。
  • 里氏替换是继承复用的基石,只有当子类可以替换父类,且软件单位的功能不受到影响时,父类才能真正被复用,而子类也能够在基类的基础上增加新的行为

1.5.接口隔离原则( ISP)

  • 不应该强迫客户程序依赖它们不用的方法。
  • 接口应该小而完备。

1.6.优先使用对象组合,而不是类继承

  • 类继承通常为“白箱复用”,对象组合通常为“黑箱复用” 。
  • 继承在某种程度上破坏了封装性,子类父类耦合度高。
  • 而对象组合则只要求被组合的对象具有良好定义的接口,耦合度低。

1.7.封装变化点

  • 使用封装来创建对象之间的分界层,让设计者可以在分界层的一侧进行修改,而不会对另一侧产生不良的影响,从而实现层次间的松耦合。

1.8.针对接口编程,而不是针对实现编程

  • 不将变量类型声明为某个特定的具体类,而是声明为某个接口。
  • 客户程序无需获知对象的具体类型,只需要知道对象所具有的接口。
  • 减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案。

2. 设计原则要求

设计原则是指导思想,将规则落实到具体的类/接口的设计、功能逻辑的划分上,可以转化成以下要求。

  • 面向抽象(抽象类、接口)编程,而不是面向实现编程
  • 接口和类的功能要尽可能的单一,避免大而全的类和接口
  • 优先使用组合,而不是继承
  • 子类的所有方法必须在父类中声明,或子类必须实现父类中声明的所有方法
  • 子类应该尽可能的与父类保持一致,不要重写父类原有逻辑
  • 如果类之间没必要直接交互,可以通过“中介”,而不是直接交互,降低耦合性
  • 实现和细节可以通过DI的方式,最大程度减少“硬编码”
  • 如果没有什么明显弊端,类应该被设计成不变的
  • 降低其他类对自身的访问权限,不要暴露内部属性成员,如果需要提供相应的访问器(属性)

3.将设计原则提升为设计经验

  • 1.设计习语 Design Idioms: Design Idioms 描述与特定编程语言相关的低层模式,技巧,惯用法。

  • 2.设计模式 Design Patterns: Design Patterns主要描述的是“类与相互通信的对象之间的组织关系,包括它们的角色、职责、协作方式等方面。

  • 3.架构模式 Architectural Patterns: Architectural Patterns描述系统中与基本结构组织关系密切的高层模式,包括子系统划分,职责,以及如何组织它们之间关系的规则。

4.重构获得模式 Refactoring to Patterns

  • 面向对象设计模式是“好的面向对象设计”,所谓“好的面向对象设计”指是那些可以满足 “应对变化,提高复用”的设计 。

  • 现代软件设计的特征是“需求的频繁变化”。设计模式的要点是“寻找变化点,然后在变化点处应用设计模式,从而来更好地应对需求的变化” .“什么时候、什么地点应用设计模式”比“理解设计模式结构本身”更为重要。

  • 设计模式的应用不宜先入为主,一上来就使用设计模式是对设计模式的最大误用。没有一步到位的设计模式。敏捷软件开发实践提倡的“Refactoring to Patterns” 是目前普遍公认的最好的使用设
    计模式的方法。

5.重构关键技法

  • 静态 --> 动态
  • 早绑定 --> 晚绑定
  • 继承 --> 组合
  • 编译时依赖 --> 运行时依赖
  • 紧耦合 --> 松耦合

设计模式概览

0.引言

1.创建型

将对象的部分创建工作延迟到子类或者其他对象,从而应对需求变化为对象创建时具体类型实现引来的冲击。

1.0.创建型概述

  • ReflectFactory反射工厂模式:通过反射,以完成⼯⼚对对象的创建。可以最⼤限度的解耦。
  • Factory Method工厂方法模式:定义⼀个⽤于创建对象的接⼝,让⼦类决定实例化哪⼀个类。⼯⼚⽅法将类的实例化延⻓到⼦类。
  • Abstract Factory抽象工厂模式(用的很少):提供一个创建一系列相关或互相 依赖对象的接口,只需要知道对象的系列,无需知道具体的对象。
  • Singleton单例模式:独一无二的存在
  • Prototype原型模式:显式实现的拷贝构造函数, 重复构造,打出“原型”
  • Builder建造者模式:组装自行车 (关注产出,不关⼼细节). 将⼀个复杂对象的构建与它的表⽰分离,使得同样的构建过程可以创建不同的表⽰。

1.1.简单工厂模式(Simple Factory)

  • 1.Factory简单工厂模式:⽤来创建⽬标对象的类,将相似对象的创建⼯作统⼀到⼀个类来完成。
  • 2.工厂类包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类。对于客户端来说,去除了对具体产品的依赖。不符合开闭原则。

1.2.工厂方法模式(Factory Method)

  • 1.工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪个类。
  • 2.工厂方法把简单工厂的内部判断逻辑移到了客户端代码,本来需要修改工厂类,现在是修 改客户端。
  • 3.简单工厂模式违背了开放-封闭原则,工厂方法模式借助多态,克服了该缺点,却保持了封装对象创建过程的优点。

1.3.抽象工厂模式(Abstract Factory)

  • 1.抽象工厂模式:提供一个创建一系列相关或互相依赖对象的接口,只需要知道对象的系列,无需知道具体的对象。
  • 2.在客户端中,具体工厂类只在初始化时出现一次,更改产品系列即可使用不同产品配置。
  • 3.利用简单工厂类替换抽象工厂类及其子类,可以使客户端不再受不同系列的影响。
  • 4.结合反射机制,Assembly.Load(“程序集名称”).CreateInstance(“命名空间”.“类名”),可以直接通过字符串创建对应类的实例。所有在简单工厂中,都可以通过反射去除switch或if,解除分支判断带来的耦合。
  • 5.反射中使用的字符串可以通过配置文件传入,避免更改代码。

1.4.单例模式(Singleton)

  • 1.单例模式:让类自身保证它只有一个实例,并提供一个全局访问点。
  • 2.多线程下单例模式可能失效,需要采取双重锁定的的方式,确保被锁定的代码同一时刻只被一个进程访问。
  • 3.饿汉式单例:即静态初始化方式,在类初始化时产生私有单例对象,会提前占用资源;渴汉式单例:在第一次被引用时将自己初始化,会产生多线程访问安全问题,需要添加双重锁定。

1.5.建造者模式(Builder)

  • 1.建造者模式:将复杂对象的创建与表示分开,使得相同的创建过程可以有不同的表示。用户只需制定需要建造的类型,不需要知道建造的过程和细节。
  • 2.指挥者是建造者模式中重要的类,用于控制建造过程,也可以隔离用户与建造过程的关联。
  • 3.建造者隐藏了产品的组装细节,若需要改变一个产品的内部表示,可以再定义一个具体的建造者。
  • 4.建造者模式是在当前创造复杂对象的算法,独立于该对象的组成部分和装配方式时适用的模式。

1.6.原型模式(Prototype)

  • 1.原型模式:用原型实例指定创建对象的种类,并通过拷贝这些原型创建对象。本质是从一个对象再创建另一个可定制的对象,并且不需要知道创建细节。
  • 2.原型抽象类的关键是有一个Clone()方法,原型具体类中复写Clone()创建当前对象的浅表副本。
  • 3.原型拷贝无需重新初始化对象,动态获取对象的运行状态。既隐藏了对象创建的细节,又提升性能。
  • 4.在具体原型类中,MemberwiseClone()方法是浅拷贝,对值类型字段诸位拷贝,对引用类型只复制引用但不会把具体的对象值拷贝过来。
  • 5.比起浅拷贝,深拷贝把引用对象的变量指向新对象,而不是原被引用的对象。对于需要深拷贝的每一层,都需要实现ICloneable原型模式。

1.7.对比总结

  • 工厂方法模式:为不同子类创建不同工厂;
  • 抽象工厂模式:为不同系列建造不同工厂;
  • 单例模式:保证实例唯一;
  • 建造者模式:为不同类组装出一套相同的方法;
  • 原型模式:实现深拷贝。

2.结构型

通过类继承或者对象组合获得更灵活的结构,从而应对需求变化为对象的结构带来的冲击。

2.0.结构型概述

  • Bridge桥接模式:牵线搭桥。将抽象部分与它的实现部分分离,使它们都可以独⽴地变化。
  • Adapter适配器模式:顾名思义,新旧对接。将⼀个接口转换成客⼾希望的另⼀个接口,使得原本由于接口不兼容而不能⼀起⼯作的那些类可以⼀起⼯作。适配器模式的别名是包装器模式(Wrapper),是⼀种结构型设计模式。
  • Decorator装饰模式:你是超人,内裤外穿。动态的给一个对象添加一些额外的职能,把所需功能按顺序串联起来并进行控制。 Decorator 提供了一种给类增加职责的方法,不是通过继承实现的,而是通过组合。
  • Composite组合模式:部分整体,树形结构,组合模式来帮忙。将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
  • Adapter适配器模式:中间的翻译官。当系统数据和行为都一致,只有接口不符合时,将一个类的接口转化为客户端期望的另一个接口。
  • Proxy代理模式:为别人做嫁衣,帮忙表白闹哪样。为其他对象提供一种代理以控制对这个对象的访问。实际上是在访问对象时引入一定程度的间接性。
  • Facade外观模式:为子系统中一组接口提供一个一致的界面,即定义一个高层接口,增加子系统的易用性。
  • Flyweight享元模式:对象复用,『享元模式』。运用共享技术有效支持大量细粒度对象。

2.1.代理模式(Proxy)

  • 1.代理模式:为其他对象提供一种代理以控制对这个对象的访问。实际上是在访问对象时引入一定程度的间接性。
  • 2.远程代理:为一个对象在不同地址空间提供局部代表,隐藏一个对象存在于不同空间的事实。如.Net加入Web引用,引入WebService,此时项目会生成WebReference的文件夹,就是代理。
  • 3.虚拟代理:根据需要创建开销很大的对象,通过它存放实例化需很长时间的真实对象。HTML中的多图,就是通过虚拟代理代替了真实图片,存储路径和尺寸。
  • 4.安全代理:控制真实对象的访问权限,用于对象应该拥有不同的访问权限时。
  • 5.智能指引:当调用真实对象时,代理处理一些另外的事情。通过代理在访问对象时增加一些内务处理。

2.2.适配器模式(Adapter)

  • 1.适配器模式:当系统数据和行为都一致,只有接口不符合时,将一个类的接口转化为客户端期望的另一个接口。
  • 2.适配器模式用于服用一些现存的类,常用在第三方接口或软件开发后期双方都不易修改的时候。

2.3.外观模式(Facade)

  • 1.外观模式:为子系统中一组接口提供一个一致的界面,即定义一个高层接口,增加子系统的易用性。
  • 2.外观模式完美体现了依赖倒转原则和迪米特法则。
  • 3.设计初期阶段,在MVC三层架构中,任意两层间建立外观Facade。
  • 4.子系统会因不断演化变得复杂,增加外观Facade提供简单简单接口减少依赖。
  • 5.在维护一个大的遗留系统时,新的开发又必须依赖其部分功能。此时,开发一个外观Facade类,从老系统中抽象出比较清晰的简单接口。让新系统只与Facade交互,而Facade与遗留代码交互所有的工作。

2.4.装饰模式(Decorator)

  • 1.装饰模式:动态的给一个对象添加一些额外的职能,把所需功能按顺序串联起来并进行控制。
  • 2.每个要装饰的功能放在单独的类中,并让这个类包装它所要修饰的对象。当需要执行特殊行为时,客户端就可以根据需要有选择的、有顺序的使用装饰功能包装对象了。
  • 3.装饰模式有效的把类的核心职能和装饰功能区分开了,并且可以去除相关类中重复的装饰逻辑。

2.5.桥接模式(Bridge)

  • 1.对象的继承关系编译时已确定,所以无法在运行时修改从父类继承的实现。由于紧耦合,父类中任何的改变必然会导致子类发生变化。当需要复用子类,但继承下来的方法不合适时,必须重写父类或用其他类替代。这种依赖性限制了灵活性和复用性。
  • 2.合成/聚合复用原则:尽量使用合成和聚合而不是继承。可以保证每个类封装集中在单个任务上,不会出现规模太大的类及继承结构。
  • 3.桥接模式:抽象类和其派生类分离,各自实现自己的对象。若系统可以从多角度分类,且每种分类都可能变化,则把多角度分离独立出来,降低耦合。

2.6.享元模式(Flyweight)

  • 1.享元模式:运用共享技术有效支持大量细粒度对象。
  • 2.在享元模式对象内部不随环境改变的共享部分是内部状态,不可共享需要通过调用传递进来的参数是外部状态。
  • 3.使用享元模式的场景包括,一个应用程序产生了大量的实例对象,占用了大量内存开销;或对象的大多数状态为外部状态,删除内部状态后可以用较少的共享对象来取代组对象。
  • 4.应用场景有正则表达式、浏览器、机器人指令集等。

2.7.组合模式(Composite)

  • 1.组合模式:将对象的组合以树形的层次结构表示,对单个对象和组合结构的操作具有一致性。
  • 2.透明方法:叶子和分枝对外接口无差别;安全方法:分枝具有添加删除叶子的接口,低层抽象接口和叶子没有。
  • 3.基本对象组合成组合,组合又可以被组合,不断递归下去,在任何用到基本对象的地方都可以使用组合对象。

2.8.对比总结

  • 代理模式:控制访问;
  • 适配器模式:将接口转换为客户端期望的形式;
  • 外观模式:整理出一套可用接口;
  • 装饰模式:动态修改类的职能;
  • 桥接模式:将多角度分类分离独立;
  • 享元模式:共享实例;
  • 组合模式:递归生成树形结构的组合对象。

3.行为型

通过类继承或者对象组合来划分类与对象间的职责,从而应对需求变化为多个交互的对象带来的冲击。

3.0.行为型概述

  • Template Method模板方法模式:金庸考试试题,你的答案在后面(子类)。定义一个操作中的算法框架,将一些步骤延迟到子类中。子类在不改变框架的前提下就可以重新定义某些特定步骤。
  • Strategy策略模式:商场满减还是打折。定义算法家族并分别封装,他们完成的工作相同,只是实现不同,可以互相替换。继承有助于析取这些算法的公共功能。此模式让算法的变化不会影响到使用算法的用户。
  • Observer观察者模式:上班摸鱼看NBA看股票。定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
  • State状态模式:今天工作状态如何(工作类–状态类)。一个对象可能拥有多种状态,当内在状态改变时允许改变行为。优化if-else状态语句。
  • Memento:备忘录模式后悔药.
  • Chain of Responsibility职责链模式:流程业务,各司其职,『责任链模式』。使多个对象都有机会处理请求,解除请求发送者和接收者的耦合。将对象连成一条链,并沿这条链传递请求直到请求被解决。
  • Iterator迭代器模式:玩转集合容器,『迭代器模式』。提供一种方法顺序遍历一个聚集对象,为不同的聚集结构提供遍历所需接口,而不暴露对象内部的表示。
  • Command命令模式:任务分发,只管下达『命令模式』即可。将请求分装为对象,将请求和执行分开,可以用不同的请求对客户参数化。可以对请求排队、通过或否决、记录日志、撤销或重做。
  • Mediator中介者模式:系列对象,依赖交互,『中介者模式』来帮忙。用一个中介对象来封装一系列对象间的交互。
  • Interpreter解释器模式:给定一种语言,定义它文法的一种表示,再定义一个解释器,使用该表示来解释语言中的句子。
  • Visitor访问者模式:这一次数据说了算,『访问者模式』。在不改变各元素的前提下定义作用于这些类的新的操作。

3.1.职责链模式(Chain of Responsibility)

  • 1.职责链模式:使多个对象都有机会处理请求,解除请求发送者和接收者的耦合。将对象连成一条链,并沿这条链传递请求直到请求被解决。
  • 2.请求交付给最小接受者,职责链中每一环保存后继的引用,使得请求有序沿链传递。
  • 3.通过合理设置后继以及分支关系,避免一个请求到了链末端依旧无法被处理,或因配置错误得不到处理的情况。

3.2.策略模式(Strategy)

  • 1.面向对象中并非类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类。
  • 2.策略模式:定义算法家族并分别封装,他们完成的工作相同,只是实现不同,可以互相替换。继承有助于析取这些算法的公共功能。此模式让算法的变化不会影响到使用算法的用户。
  • 3.策略与工厂模式结合,使客户端需要认识的类减少,耦合度更加降低。
  • 4.策略模式可以简化单元测试,因为每个算法可以通过自己的接口单独测试。
  • 5.只要在不同时间内应用不同的业务规则,就可以考虑用策略模式来处理这种变化的可能性。

3.3.状态模式(State)

  • 1.拥有过多分支的过长方法违背了单一职责原则,而且当需求变化时修改代码往往会违背开放-封闭原则,应该将分支变成一不同小类,将状态的判断逻辑转移到小类中。
  • 2.状态模式:一个对象可能拥有多种状态,当内在状态改变时允许改变行为。
  • 3.状态模式的好处是将与特定状态有关的行为局部化,并将不同状态的行为分隔开。

3.4.观察者模式(Observer)

  • 1.观察者模式:多个观察者对象同时监听某一主题(通知者)对象,当该主题对象状态变化时会通知所有观察者对象,使它们能更新自己。
  • 2.具体观察者保存一个指向具体主题对象的引用,抽象主题保存一个抽象观察者的引用集合,提供一个可以添加或删除观察者的接口。
  • 3.抽象模式中有两方面,一方面依赖另一方面,使用观察者模式可将两者独立封装,解除耦合。
  • 4.观察者模式让主题和观察者双方都依赖于抽象接口,而不依赖于具体。
  • 5.委托就是一种引用方法类型。委托可看作函数的类,委托的实例代表具体函数。在主题对象内声明委托,不再依赖抽象观察者。
  • 6.一个委托可以搭载多个相同原形和形式(参数和返回值)的方法,这些方法不需要属于一个类,且被依次唤醒。

3.5.迭代器模式(Iterator)

  • 1.迭代器模式:提供一种方法顺序遍历一个聚集对象,为不同的聚集结构提供遍历所需接口,而不暴露对象内部的表示。
  • 2.在高级编程语言如c#、c++、java等,都已经把迭代器模式设计进语言的一部分。
  • 3.迭代器模式分离了对象的遍历行为,既不暴露内部结构又可以让外部代码透明的访问集合内部的数据。

3.6.备忘录模式(Memento)

  • 1.备忘录模式:不破坏封装,获取对象内部状态并在其之外保存该对象,以便其未来恢复到当前状态。
  • 2.Orginator负责创建Memento,Memento封装Originator状态细节,Caretaker负责保管和交付Memento。
  • 3.备忘录模式适用于需要维护历史状态的对象,或只需要保存原类属性中的小部分。

3.7.命令模式(Command)

  • 1.命令模式:将请求分装为对象,将请求和执行分开,可以用不同的请求对客户参数化。可以对请求排队、通过或否决、记录日志、撤销或重做。
  • 2.基于敏捷开发原则,不要给代码添加基于猜测而实际不需要的功能,在需要的时候通过重构实现。

3.8.模板方法模式(Template Method)

  • 1.模板方法模式:定义一个操作中的算法框架,将一些步骤延迟到子类中。子类在不改变框架的前提下就可以重新定义某些特定步骤。
  • 2.当不变和可变的行为在子类中混到一起时,可以通过把重复的行为移到同一地方,帮助子类摆脱重复不变行为的纠缠。

3.9.中介者模式(Mediator)

  • 1.中介者模式:用一个中介对象来封装一系列对象间的交互。
  • 2.中介者模式在系统中易用也容易被误用,当系统中出现了多对多的交互复杂的对象群时,更应考虑设计的问题。
  • 3.由于控制集中化,中介者模式将交互复杂性变成了中介者的复杂性,中介者类会比任何一个同事类都复杂。
    中介者模式应用的场合有,一组对象以定义良好但复杂的方式进行通信,以及想定制一个分布在多个类中的行为却不想产生太多子类。

3.10.解释器模式(Interpreter)

  • 1.解释器模式:给定一种语言,定义它文法的一种表示,再定义一个解释器,使用该表示来解释语言中的句子。
    如果一种特定类型发生的频率足够高,就可以将其实例表达为一个句子,构建解释器来解析。
    2.解释器模式就是用“迷你语言”来表现程序要解决的问题,将句子抽象为语法树。由于各个节电的类大体相同,便于修改、扩展和实现。
    3.解释器为文法中的每条规则定义了一个类,当文法过多时将难以维护,建议使用其他技术如语法分析程序或编译器生成器处理。

3.11.访问者模式(Visitor)

  • 1.访问者模式:在不改变各元素的前提下定义作用于这些类的新的操作。
  • 2.访问者模式使用双分派,将数据结构和作用于结构上的操作解耦,意味着执行的操作决定于请求的种类和接收者的状态。
  • 3.如果系统具有较为稳定的数据结构,又有易于变化的算法操作,则适合使用访问者模式。

3.12.对比总结

  • 职责链模式:按顺序让负责的对象们依次处理;
  • 策略模式:将算法族抽象封装;
  • 状态模式:将复杂的状态转移方式下发到每个状态内部;
  • 观察者模式:发布和订阅;
  • 迭代器模式:遍历容器;
  • 备忘录模式:在对象之外备份及恢复;
  • 命令模式:封装请求与执行分开;
  • 模板方法模式:提炼共有方法。
  • 中介者模式:用中介对象封装交互。
  • 解释器模式:迷你语言;
  • 访问者模式:解耦数据结构及操作。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值