Head First Design Mode(14)-复合模式(MVC)

该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动!

 

复合模式:

    模式的模式;

    本章主要介绍如何使用多种模式解决具体问题,以及复合模式的代表MVC的使用;

 

模式通常被一起使用,并被组合在同一个设计解决方案中;

复合模式在一个解决方案中结合两个或多个模式,已解决一般或重复发生的问题;

 

鸭子模拟器示例:

    一堆Quackable,会叫的鸭子;

    出现一只鹅,他希望自己像个Quackable;

    呱呱叫学家决定要计算呱呱叫声的次数;

    担心忘记给Quackable加上QuackCounter装饰者怎么办;

    又是鸭子、又是鹅、又是Quackable…….管理上的困扰;

    任何呱呱叫时,呱呱叫学家都希望能被告知;

 

接下来看如何使用设计模式解决上述问题:

1.设计创建一个Quackable接口:    

【Code-Quackable.java】

public interface Quackable{
    public void quack();
    
}

2.设计一些具体的鸭子实现Quackable接口:

【Code-Demo1Duck.java】

public class Demo1Duck implements Quackable{
    
    public void quack(){
        System.out.println("Quack!");
    }
    
}

【Code-Demo2Duck.java】

public class Demo2Duck implements Quackable{
    
    public void quack(){
        System.out.println("Quack!");
    }
    
}

【Code-Demo3Duck.java】

public class Demo3Duck implements Quackable{
    
    public void quack(){
        System.out.println("Quack!");
    }
    
}

加入了鸭鸣器和橡皮鸭,他们的叫声有些不同:

【Code-Duckcall.java】

public class Duckcall implements Quackable{
    
    public void quack(){
        System.out.println("Kwak!");
    }
    
}

【Code-RubberDuck.java】

public class RubberDuck implements Quackable{
    
    public void quack(){
        System.out.println("Squeak!");
    }
    
}

3.新建鸭子模拟器:

【Code-DuckSimulator.java】

public class DuckSimulator{
    public static void main(String[] args){
        DuckSimulator simulator = new DuckSimulator();
        simulator.simulator();
    }
    
    void simulator(){
        Quackable demo1Duck = new Demo1Duck();
        Quackable demo2Duck = new Demo2Duck();
        Quackable demo3Duck = new Demo3Duck();
        Quackable duckcall = new Duckcall();
        Quackable rubberDuck = new RubberDuck();
        
        simulator(demo1Duck);
        simulator(demo2Duck);
        simulator(demo3Duck);
        simulator(duckcall);
        simulator(rubberDuck);
    }
    
    void simulator(Quackable duck){
        duck.quack();
    }
}

运行:

bogon:鸭子模拟器 huaqiang$ javac *.java
bogon:鸭子模拟器 huaqiang$ java DuckSimulator
Quack!
Quack!
Quack!
Kwak!
Squeak!

4.鹅也出现了:鹅是“咯咯”叫;

【Code-Goose.java】

public class Goose {
    public void honk(){
        System.out.println("Honk!!");
    }
}

5.想要在鸭子模拟器中使用鹅,我们需要鹅适配器:

【Code-GooseAdapter.java】

public class GooseAdapter implements Quackable{
    Goose goose;
    
    public GooseAdapter(Goose goose){
        this.goose = goose;
    }
    
    public void quack(){
        goose.honk();
    }
    
}

6.这样我们就可以在鸭子模拟器中使用鹅了:

【Code-DuckSimulator.java】

public class DuckSimulator{
    public static void main(String[] args){
        DuckSimulator simulator = new DuckSimulator();
        simulator.simulator();
    }
    
    void simulator(){
        Quackable demo1Duck = new Demo1Duck();
        Quackable demo2Duck = new Demo2Duck();
        Quackable demo3Duck = new Demo3Duck();
        Quackable duckcall = new Duckcall();
        Quackable rubberDuck = new RubberDuck();
        Quackable gooseDuck = new GooseAdapter(new Goose());

        simulator(demo1Duck);
        simulator(demo2Duck);
        simulator(demo3Duck);
        simulator(duckcall);
        simulator(rubberDuck);
        simulator(gooseDuck);

    }
    
    void simulator(Quackable duck){
        duck.quack();
    }
}

7.运行:

bogon:鸭子模拟器 huaqiang$ javac *.java
bogon:鸭子模拟器 huaqiang$ java DuckSimulator
Quack!
Quack!
Quack!
Kwak!
Squeak!
Honk!!

8.一群鸭子中有多少呱呱叫声,我们要让呱呱叫学着知道叫声的次数:

    我们创建一个装饰者,将鸭子包装进装饰者对象,给鸭子添加一些新的行为(计算次数),不必修改鸭子代码;

【Code-QuackCounter.java】

public class QuackCounter implements Quackable{
    
    Quackable duck;
    static int numberOfQuacks;
    
    public QuackCounter(Quackable duck){
        this.duck = duck;
    }
    
    public void quack(){
        duck.quack();
        numberOfQuacks++;
    }
    
    public static int getQuacks(){
        return numberOfQuacks;
    }
}

9.我们需要更新此模拟器,以便创建被装饰的鸭子:

【Code-DuckSimulator.java】

public class DuckSimulator{
    public static void main(String[] args){
        DuckSimulator simulator = new DuckSimulator();
        simulator.simulator();
    }
    
    void simulator(){
        Quackable demo1Duck = new QuackCounter(new Demo1Duck());
        Quackable demo2Duck = new QuackCounter(new Demo2Duck());
        Quackable demo3Duck = new QuackCounter(new Demo3Duck());
        Quackable duckcall = new QuackCounter(new Duckcall());
        Quackable rubberDuck = new QuackCounter(new RubberDuck());
        Quackable gooseDuck = new GooseAdapter(new Goose());

        simulator(demo1Duck);
        simulator(demo2Duck);
        simulator(demo3Duck);
        simulator(duckcall);
        simulator(rubberDuck);
        simulator(gooseDuck);

        System.out.println("Ducks quacked " + QuackCounter.getQuacks() + " times.");
    }
    
    void simulator(Quackable duck){
        duck.quack();
    }
}

运行:

bogon:鸭子模拟器 huaqiang$ javac *.java
bogon:鸭子模拟器 huaqiang$ java DuckSimulator
Quack!
Quack!
Quack!
Kwak!
Squeak!
Honk!!
Ducks quacked 5 times.

10.只有装饰过的鸭子叫才会被统计,最好将创建鸭子的行为集中-可以用工厂生产鸭子:

    我们创建一个工程,生产装饰过的鸭子,为产生不同类型的鸭子的产品家族,需要抽象工厂模式;

【Code-AbstractDuckFactory.java】

public abstract class AbstractDuckFactory{
    //每种方法创建一种鸭子
    public abstract Quackable createDemo1Duck();
    public abstract Quackable createDemo2Duck();
    public abstract Quackable createDemo3Duck();
    public abstract Quackable createDuckcall();
    public abstract Quackable createRubberDuck();
}

创建一个工厂-生产普通鸭子:

【Code-DuckFactory.java】

public class DuckFactory extends AbstractDuckFactory{
    
    
    //每种方法创建一种鸭子
    public Quackable createDemo1Duck(){
        return new Demo1Duck();
    }
    public Quackable createDemo2Duck(){
        return new Demo2Duck();
    }
    public Quackable createDemo3Duck(){
        return new Demo3Duck();
    }
    public Quackable createDuckcall(){
        return new Duckcall();
    }
    public Quackable createRubberDuck(){
        return new RubberDuck();
    }
}

创建一个工厂-生产装饰过计数行为的鸭子:

【Code-CountingDuckFactory.java】

public class CountingDuckFactory extends AbstractDuckFactory{
    
    
    //每种方法创建一种鸭子
    public Quackable createDemo1Duck(){
        return new QuackCounter(new Demo1Duck());
    }
    public Quackable createDemo2Duck(){
        return new QuackCounter(new Demo2Duck());
    }
    public Quackable createDemo3Duck(){
        return new QuackCounter(new Demo3Duck());
    }
    public Quackable createDuckcall(){
        return new QuackCounter(new Duckcall());
    }
    public Quackable createRubberDuck(){
        return new QuackCounter(new RubberDuck());
    }
}

11.设置模拟器来使用这个工厂(CountingDuckFactory):

【Code-DuckSimulator.java】

public class DuckSimulator{
    public static void main(String[] args){
        DuckSimulator simulator = new DuckSimulator();
        AbstractDuckFactory duckFactory = new CountingDuckFactory();
        simulator.simulator(duckFactory);
    }
    
    void simulator(AbstractDuckFactory duckFactory){
        Quackable demo1Duck = duckFactory.createDemo1Duck();
        Quackable demo2Duck = duckFactory.createDemo2Duck();
        Quackable demo3Duck = duckFactory.createDemo3Duck();
        Quackable duckcall = duckFactory.createDuckcall();
        Quackable rubberDuck = duckFactory.createRubberDuck();
        Quackable gooseDuck = new GooseAdapter(new Goose());

        simulator(demo1Duck);
        simulator(demo2Duck);
        simulator(demo3Duck);
        simulator(duckcall);
        simulator(rubberDuck);
        simulator(gooseDuck);

        System.out.println("Ducks quacked " + QuackCounter.getQuacks() + " times.");
    }
    
    void simulator(Quackable duck){
        duck.quack();
    }
}

运行:

bogon:鸭子模拟器 huaqiang$ javac *.java
bogon:鸭子模拟器 huaqiang$ java DuckSimulator
Quack!
Quack!
Quack!
Kwak!
Squeak!
Honk!!
Ducks quacked 5 times.

12.将鸭子视作一个集合(子集合),管理员想要管理所有的鸭子:

    创建一群鸭子(一群Quackable),使用组合模式像对单个对象一样对待对象集合;

组合节点:【Code-Flock.java】,叶子节点就是具体的鸭子;

import java.util.*;

public class Flock implements Quackable{
    ArrayList<Quackable> quackers = new ArrayList<Quackable>();
    
    public void add(Quackable quacker){
        quackers.add(quacker);
    }
    
    public void quack(){
        Iterator iterator = quackers.iterator();
        while(iterator.hasNext()){
            Quackable quacker = (Quackable)iterator.next();
            quacker.quack();
        }    
    }
}

13.修改模拟器 让鸭子进入组合结构:(注意透明性和安全性之间的权衡)

【Code-DuckSimulator.java】

public class DuckSimulator{
    public static void main(String[] args){
        DuckSimulator simulator = new DuckSimulator();
        AbstractDuckFactory duckFactory = new CountingDuckFactory();
        simulator.simulator(duckFactory);
    }
    
    void simulator(AbstractDuckFactory duckFactory){
        Quackable demo1Duck = duckFactory.createDemo1Duck();
        Quackable demo2Duck = duckFactory.createDemo2Duck();
        Quackable demo3Duck = duckFactory.createDemo3Duck();
        Quackable duckcall = duckFactory.createDuckcall();
        Quackable rubberDuck = duckFactory.createRubberDuck();
        Quackable gooseDuck = new GooseAdapter(new Goose());

        Flock flockOfDucks = new Flock();
        flockOfDucks.add(demo1Duck);
        flockOfDucks.add(demo2Duck);
        flockOfDucks.add(demo3Duck);
        
        Flock flockOfAllDucks = new Flock();
        flockOfAllDucks.add(flockOfDucks);
        flockOfAllDucks.add(duckcall);
        flockOfAllDucks.add(rubberDuck);
        flockOfAllDucks.add(gooseDuck);

        simulator(flockOfAllDucks);//test all ducks
        simulator(flockOfDucks);//test part normal ducks

        System.out.println("Ducks quacked " + QuackCounter.getQuacks() + " times.");
    }
    
    void simulator(Quackable duck){
        duck.quack();
    }
}

运行:

bogon:鸭子模拟器 huaqiang$ javac *.java -Xlint:unchecked
bogon:鸭子模拟器 huaqiang$ java DuckSimulator
Quack!
Quack!
Quack!
Kwak!
Squeak!
Honk!!
Quack!
Quack!
Quack!
Ducks quacked 8 times.

14.现在,有什么办法让我们能持续追踪个别鸭子的实时呱呱叫吗?—— 可以使用观察者模式;

我们需要一个Observable接口:

    Observable是被观察者的对象,需要注册和通知观察者的方法;(为了简单这里省略了移除观察者的方法)

    QuackObservable是一个接口,任何想被观察的Quackable都必须实现QuackObservable接口;

【Code-QuackObservable.java】

public interface QuackObservable {
    public void registerObserver(Observer observer);
    public void notifyObservers();
}

接下来让所有的Quackable都实现此接口:直接让Quackable扩展自此接口;

【Code-Quackable.java】

public interface Quackable extends QuackObservable{
    public void quack();
    
}

15.由于让Quackable扩展自QuackObservable,导致所有的Duck都需要实现QuackObservable接口定义的API;

    为了使用一份代码,我们新建一个实现QuackObservable接口的辅助类Observable,每一个Duck都将各自实现的QuackObservable接口API委托给Observable辅助类:

【Code-Observable.java】

import java.util.*;

public class Observable implements QuackObservable{
    ArrayList<Observer> observers = new ArrayList<Observer>();
    QuackObservable duck;
    
    public Observable(QuackObservable duck){
        this.duck = duck;
    }
    
    public void registerObserver(Observer observer){
        observers.add(observer);
    }
    public void notifyObservers(){
        Iterator iterator = observers.iterator();
        while (iterator.hasNext()){
            Observer observer = (Observer)iterator.next();
            observer.update(duck);
        }
    }
    
}

16.现在需要修改众多Quackable类,使用辅助类Observable:

【Code-Demo1Duck.java】

public class Demo1Duck implements Quackable{
    Observable observable;
    
    public Demo1Duck(){
        observable = new Observable(this);
    }
    
    public void quack(){
        System.out.println("Quack!");
        notifyObservers();
    }
    
    public void registerObserver(Observer observer){
        observable.registerObserver(observer);
    }
    
    public void notifyObservers(){
        observable.notifyObservers();
    }    
}

【Code-Demo2Duck.java】

public class Demo2Duck implements Quackable{
    Observable observable;
    
    public Demo2Duck(){
        observable = new Observable(this);
    }
    
    public void quack(){
        System.out.println("Quack!");
        notifyObservers();
    }
    
    public void registerObserver(Observer observer){
        observable.registerObserver(observer);
    }
    
    public void notifyObservers(){
        observable.notifyObservers();
    }  
}

【Code-Demo3Duck.java】

public class Demo3Duck implements Quackable{
    Observable observable;
    
    public Demo3Duck(){
        observable = new Observable(this);
    }
    
    public void quack(){
        System.out.println("Quack!");
        notifyObservers();
    }
    public void registerObserver(Observer observer){
        observable.registerObserver(observer);
    }
    
    public void notifyObservers(){
        observable.notifyObservers();
    }  
}

【Code-Duckcall.java】

public class Duckcall implements Quackable{
    Observable observable;
    
    public Duckcall(){
        observable = new Observable(this);
    }
    
    public void quack(){
        System.out.println("Kwak!");
        notifyObservers();
    }
    public void registerObserver(Observer observer){
        observable.registerObserver(observer);
    }
    
    public void notifyObservers(){
        observable.notifyObservers();
    }
}

【Code-RubberDuck.java】

public class RubberDuck implements Quackable{
    Observable observable;
    
    public RubberDuck(){
        observable = new Observable(this);
    }
    public void quack(){
        System.out.println("Squeak!");
        notifyObservers();
    }
    public void registerObserver(Observer observer){
        observable.registerObserver(observer);
    }
    
    public void notifyObservers(){
        observable.notifyObservers();
    }
}

【Code-GooseAdapter.java】

public class GooseAdapter implements Quackable{
    Goose goose;
    Observable observable;
    
    public GooseAdapter(Goose goose){
        this.goose = goose;
        observable = new Observable(this);
    }
    
    public void quack(){
        goose.honk();
        notifyObservers();
    }
    public void registerObserver(Observer observer){
        observable.registerObserver(observer);
    }
    
    public void notifyObservers(){
        observable.notifyObservers();
    } 
}

【Code-QuackCounter.java】

public class QuackCounter implements Quackable{
    
    Quackable duck;
    static int numberOfQuacks;
    
    public QuackCounter(Quackable duck){
        this.duck = duck;
    }
    
    public void quack(){
        duck.quack();
        numberOfQuacks++;
    }
    
    public static int getQuacks(){
        return numberOfQuacks;
    }
    public void registerObserver(Observer observer){
        duck.registerObserver(observer);
    }
    
    public void notifyObservers(){
        duck.notifyObservers();
    } 
}

【Code-Flock.java】

import java.util.*;

public class Flock implements Quackable{
    ArrayList<Quackable> quackers = new ArrayList<Quackable>();

    public void add(Quackable quacker){
        quackers.add(quacker);
    }
    
    public void quack(){
        Iterator iterator = quackers.iterator();
        while(iterator.hasNext()){
            Quackable quacker = (Quackable)iterator.next();
            quacker.quack();
        }    
    }
    public void registerObserver(Observer observer){
        Iterator iterator = quackers.iterator();
        while(iterator.hasNext()){
            Quackable quacker = (Quackable)iterator.next();
            quacker.registerObserver(observer);
        } 
    }
    
    public void notifyObservers(){
        Iterator iterator = quackers.iterator();
        while(iterator.hasNext()){
            Quackable quacker = (Quackable)iterator.next();
            quacker.notifyObservers();
        }
    } 
}

17.我们已经使用了Observer,现在我们要做的就是把Observer端完成:

    包括Observer接口和一些观察者;

【Code-Observer.java】

public interface Observer{
    public void update(QuackObservable duck);
}

【Code-Quackologist.java】

public class Quackologist implements Observer{
    
    public void update(QuackObservable duck){
        System.out.println("Quackologist:" + duck + " just quacked.");
    }

}

值得注意的是:现在如果想观察一组鸭子也很方便,直接观察一个Flock就行了;

 

18.更新模拟器:

【Code-DuckSimulator.java】

public class DuckSimulator{
    public static void main(String[] args){
        DuckSimulator simulator = new DuckSimulator();
        AbstractDuckFactory duckFactory = new CountingDuckFactory();
        simulator.simulator(duckFactory);
    }
    
    void simulator(AbstractDuckFactory duckFactory){
        Quackable demo1Duck = duckFactory.createDemo1Duck();
        Quackable demo2Duck = duckFactory.createDemo2Duck();
        Quackable demo3Duck = duckFactory.createDemo3Duck();
        Quackable duckcall = duckFactory.createDuckcall();
        Quackable rubberDuck = duckFactory.createRubberDuck();
        Quackable gooseDuck = new GooseAdapter(new Goose());

        Flock flockOfDucks = new Flock();
        flockOfDucks.add(demo1Duck);
        flockOfDucks.add(demo2Duck);
        flockOfDucks.add(demo3Duck);
        
        Flock flockOfAllDucks = new Flock();
        flockOfAllDucks.add(flockOfDucks);
        flockOfAllDucks.add(duckcall);
        flockOfAllDucks.add(rubberDuck);
        flockOfAllDucks.add(gooseDuck);

        Quackologist quackologist = new Quackologist();
        flockOfDucks.registerObserver(quackologist);
        
        simulator(flockOfAllDucks);//test all ducks
        simulator(flockOfDucks);//test part normal ducks

        System.out.println("Ducks quacked " + QuackCounter.getQuacks() + " times.");
        
        
        
    }
    
    void simulator(Quackable duck){
        duck.quack();
    }
}

运行:

bogon:鸭子模拟器 huaqiang$ javac *.java
bogon:鸭子模拟器 huaqiang$ java DuckSimulator
Quack!
Quackologist:Demo1Duck@7852e922 just quacked.
Quack!
Quackologist:Demo2Duck@4e25154f just quacked.
Quack!
Quackologist:Demo3Duck@70dea4e just quacked.
Kwak!
Squeak!
Honk!!
Quack!
Quackologist:Demo1Duck@7852e922 just quacked.
Quack!
Quackologist:Demo2Duck@4e25154f just quacked.
Quack!
Quackologist:Demo3Duck@70dea4e just quacked.
Ducks quacked 8 times.

我们发现,每次被观察的鸭子叫时,都会通知观察者;

 

上述代码结构类图:

 


 

复合模式之王:

    Model-View-Controller(模型-视图-控制器)模式;

    MVC是一种泛型,它构造代码成为功能段,达到复用的目的;

 

视图对象通常是控件,用来显示和编辑;但视图并不知道模型;视图和模型之间的数据流通是由控制器居中协调进行的;

 

MVC是由数个设计模式结合起来的模式;

 

认识MVC(播放器示例):

    有的时候,控制器也可以直接向模型注册观察者,继而改变视图的显示(即第4步是由控制器指向模型的);

 

 

MVC的组成:

    模型利用观察者让控制器和视图可以随最新的状态改变和更新;

    视图和控制器实现了策略模式,控制器是视图的行为,如果希望不同行为,可以换一个控制器;

    视图内部使用组合模式来管理窗口、按钮以及其他显示组件;

 

视图是一个对象,可以被调整使用不同的策略,而控制器提供了策略;

    视图只关心可视的部分,将行为委托给控制器处理,策略模式使得视图和模型之间的关系解耦,因为控制器负责和模型交互来传递用户的请求;视图并不知道工作如何完成;

 

模型对视图和控制器没有依赖;

    模型实现应用逻辑,并决定如何响应动作;

    控制器也做一些决定,决定调用哪个模型的哪个方法;但这不算应用逻辑;

    应用逻辑指的是管理和操纵你的模型中的数据的代码;

 

有人吧MVC的控制器描述为视图和模型的中介者:

    中介者的意图是封装对象之间的交互,不让两个对象之间互相显示引用,以达到松耦合的目的;

    某种程度上,控制器可以被视为中介者:视图通过控制器设置模型状态,也通过控制器获取模型状态;

 

总结:

1.MVC是复合模式,结合了观察者、策略模式和组合等模式;

2.模式使用观察者模式,以便观察者更新,同时保持两者间解耦;

3.控制器是视图的策略,视图可以使用不同的控制器,得到不同的行为;

4.视图使用组合模式实现,用户界面通常嵌套组件;

5.这些模式一起,完成MVC三层解耦,保持设计干净又有弹性;

6.适配器模式用来将新的模型是配成已有的视图和控制器;

    

 

OO基础:

    抽象;

    封装

    继承;

    多态;

OO原则:

    封装变化

    多用组合,少用继承

    针对接口编程,不针对实现编程

    为交互对象之间的松耦合设计而努力;

    类应该对扩展开放,对修改关闭;

    依赖抽象,不要依赖具体类;

    只和朋友交谈(最少知识原则);

    别找我,我会找你(好莱坞原则:由超类主控一切,需要的时候自然会去调用子类);

    类应该只有一个改变的理由(单一职责原则);

OO模式:

    策略模式:定义算法族,分别封装起来,让他们之间互相替换,此模式让算法的变化独立于使用算法的客户;

    观察者模式:在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新;

    装饰者模式:动态地将责任附加到对象上;想要扩展功能,装饰者提供有别于继承的另一种选择;

    简单工厂模式;

    工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个;工厂方法让类把实例化推迟到子类;

    抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确具体的类;

    单件模式:确保一个类只有一个实例,并提供全局访问点;

    命令模式:将请求封装成对象,这可以让你使用不同的请求,队列或者日志请求来参数化其他对象;命令模式也支持撤销操作;

    适配器模式:将一个类的接口转换成客户期待的另一个接口,适配器让原来不兼容的类可以合作无间;

    外观模式:提供了一个统一的接口,用来访问子系统中的一群接口;外观模式定义了高层接口,让子系统更容易使用;

    模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中;模板方法使得子类可以在不改变算法结构的情况下,重新定义/捕获算法中的某些步骤;

    迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示;

    组合模式:允许你将对象组成树形结构来表现整体/部分的层次结构;组合能让客户以一致的方式处理个别对象和对象组合;

    状态模式:允许对象在内部状态改变时改变他的行为,对象看起来好像修改了它的类;

    代理模式:为另一个对象提供一个替身或占位符以访问这个对象;

    ——复合模式:结合两个或两个以上的模式,组成一个解决方案,解决一再发生的一般性问题;

 


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值