Java基础篇--设计模式

目录

前言

设计模式

创建型模式

单例模式

工厂方法模式

抽象工厂模式

建造者模式

原型模式

结构型模式

适配器模式

桥接模式

组合模式

装饰模式

外观模式

亨元模式

代理模式

行为型模式:

访问者模式

模板模式

策略模式

状态模式

观察者模式

备忘录模式

中介者模式

迭代器模式

解释器模式

命令模式

责任链模式


前言

带着问题学java系列博文之java基础篇。从问题出发,学习java知识。


设计模式

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码,优雅快捷地实现特定需求。Java中共计总结出了23种设计模式,这些设计模式又主要分为三大类,分别是:创建型、行为型和结构型。

 

创建型模式

创建型模式:对象实例化的模式,创建型模式用于解耦对象的实例化过程。

单例模式

单例模式:用于对象实例化,保证全局仅有一个对象实例,且线程同步。主要实现方式有:懒汉模式、饿汉模式、双检锁模式以及静态内部类模式,还包含一个特殊的实现方式,枚举类。下面的代码范例都一一实现了,并在注释中分析了各个实现方式的优缺点。

/**
 * 单例模式
 */
public class Singleton {
    /*
    //懒汉模式
    private static Singleton mSingleton;

    private Singleton(){}

    public static Singleton getInstance(){
        if (mSingleton == null){
            mSingleton = new Singleton();
        }
        return mSingleton;
    }


    //饿汉模式
    private static Singleton mInstance = new Singleton();

    private Singleton(){}

    public static Singleton getmInstance(){
        return mInstance;
    }
    */
    //上面实现的两种模式有很大的缺陷:
    //懒汉模式:优点是仅在使用的时候才初始化,减少内存占用;但是存在并发同步危险;
    //饿汉模式:在一开始就初始化,占用内存


    /*
    //改进的懒汉模式 dcl-双检锁
    private static Singleton mInstance;

    private Singleton(){}

    public static Singleton getmInstance(){
        if (mInstance == null){
            synchronized (Singleton.class){
                if (mInstance == null){
                    mInstance = new Singleton();
                }
            }
        }
        return mInstance;
    }

    //改进之后的懒汉模式保证了同步,且减少了每次调用都需要同步的消耗。但是仍会存在小概率失败(双重检查锁定失效)
    */

    //静态内部类方式
    private static Singleton mInstance;
    private Singleton(){}
    public static Singleton getmInstance(){
        return SingletonHolder.singleton;
    }
    private static class SingletonHolder{
        private static final Singleton singleton = new Singleton();
    }
    //这种方式既保证了线程同步,也保证了实例的唯一性,同时只有在使用时才会实例化,推荐使用这种方式。


    //实现单例的最佳方式:枚举
    public enum SinletonEnum{
        INSTANCE;
        public void otherMethods(){}
    }

    public enum Color{
        //添加参数的枚举
        RED(1),GREEN(2),BLACK(3);
        private int code;
        Color(int code){
            this.code = code;
        }

        public int getCode() {
            return code;
        }
    }
}

工厂方法模式

工厂方法模式属于工厂模式的一类,将实例化对象的工作进行封装,实现业务代码与对象实例化之间的解耦。类似现实生活中,要用到一个电器,则由电器工厂生产一个,我们直接从工厂拿就可以了,而不用关心如何生产。

简单工厂模式(静态工厂模式)属于工厂方法模式的特例:

public abstract class BMW {
}

public class BMW520 extends BMW {
    public BMW520() {
        System.out.println("生产-》BMW520");
    }
}

public class BMW530 extends BMW {
    public BMW530() {
        System.out.println("生产-》bmw530");
    }
}

/**
 * 简单工厂模式
 * 优点:实现简单,代码逻辑清晰易懂
 * 缺点:工厂类不遵循开闭原则,每增加或者减少一个具体的产品类,都需要修改工厂类代码,增加case或者删除case
 */
public class BMWFactory {
    public static BMW createBMW(int type){
        switch (type){
            case 520:
                return new BMW520();
            case 530:
                return new BMW530();
                default:
                    return null;
        }
    }

    public static void main(String[] args) {
        BMW bmw520 = BMWFactory.createBMW(520);
        BMW bmw530 = BMWFactory.createBMW(530);
    }
}

为了符合开闭原则,工厂方法模式对简单工厂进行了拓展:

public abstract class BMW {
}

public class BMW520 extends BMW {
    public BMW520() {
        System.out.println("生产-》BMW520");
    }
}

public class BMW530 extends BMW {
    public BMW530() {
        System.out.println("生产-》bmw530");
    }
}

public interface BMWFactory {
    BMW createBMW();
}

public class BMW520Factory implements BMWFactory {
    @Override
    public BMW createBMW() {
        return new BMW520();
    }
}

public class BMW530Factory implements BMWFactory {
    @Override
    public BMW createBMW() {
        return new BMW530();
    }
}

/**
 * 工厂方法模式
 * 优点:实现简单,代码逻辑清晰易理解,且遵循开闭原则(新增产品类,不需要改动已有代码,只需要按照工厂接口,实现一个具体的产品工厂即可)
 * 缺点:需要实现诸多的工厂类,随着产品类的增多,工厂类也越来越多
 */
public class Customer {
    public static void main(String[] args) {
        BMW bmw520 = new BMW520Factory().createBMW();
        BMW bmw530 = new BMW530Factory().createBMW();
    }
}

抽象工厂模式

拿上面的例子继续,BMW升级,加配空调、沙发,形成一个产品族。BMW520配置空调A和真皮沙发;BMW530配置空调B和布艺沙发。即抽象工厂区别于工厂方法模式是,抽象工厂模式是抽象工厂具有生产产品族的能力,由于具体的工程实现类实现生产一组特定的产品。

public abstract class AirConditioner {
}

public class AirConditionerA extends AirConditioner {
    public AirConditionerA() {
        System.out.println("生产空调A");
    }
}

public class AirConditionerB extends AirConditioner {
    public AirConditionerB() {
        System.out.println("生产空调B");
    }
}

public abstract class Sofa {
}

public class LeatherSofa extends Sofa {
    public LeatherSofa() {
        System.out.println("生产真皮沙发");
    }
}

public class ClothSofa extends Sofa {
    public ClothSofa() {
        System.out.println("生产布艺沙发");
    }
}

public interface BMWFactory {
    BMW createBMW();
    AirConditioner createAirConditioner();
    Sofa createSofa();
}

public class BMW520Factory implements BMWFactory {
    @Override
    public BMW createBMW() {
        createAirConditioner();
        createSofa();
        return new BMW520();
    }

    @Override
    public AirConditioner createAirConditioner() {
        return new AirConditionerA();
    }

    @Override
    public Sofa createSofa() {
        return new LeatherSofa();
    }
}

public class BMW530Factory implements BMWFactory {
    @Override
    public BMW createBMW() {
        createAirConditioner();
        createSofa();
        return new BMW530();
    }

    @Override
    public AirConditioner createAirConditioner() {
        return new AirConditionerB();
    }

    @Override
    public Sofa createSofa() {
        return new ClothSofa();
    }
}


/**
 * 抽象工厂模式
 * 由具体的工厂生产一组产品,对应特定的产品族
 */
public class Customer {
    public static void main(String[] args) {
        BMW bmw520 = new BMW520Factory().createBMW();
        BMW bmw530 = new BMW530Factory().createBMW();
    }
}

建造者模式

建造者模式(创造者模式):实例化具有多个参数,并且存在部分参数必须赋初值、部分参数可选赋值的对象时,相较于使用多个构造器或者使用javabean,是一种更优越的实现方式。比如,一台小米电视,它有几个参数必须初始化时设定:cpu参数、屏幕参数;有几个参数可选:gpu参数、分辨率、外设。简单做法,可以写多个构造器,参数列表从0到所有参数;或者可以写一系列getter和setter,初始化之后,通过setter设定初值。这两个方法都容易在使用的时候出错,参数传递错误,遗漏某个属性没有setter等等。而使用建造者模式就可以很好的避免这些情况,对于必须赋初值的属性,强制要求赋初值,对于可选的属性,则提供可选设定方法。

/**
 * 建造者模式
 */
public class MiTV5 {
    private String cpu;
    private String screen;
    private String gpu;
    private String resolution;
    private String peripheral;

    private MiTV5(Builder builder) {
        cpu = builder.cpu;
        screen = builder.screen;
        gpu = builder.gpu;
        resolution = builder.resolution;
        peripheral = builder.peripheral;
    }

    public static class Builder{
        private String cpu;
        private String screen;
        private String gpu;
        private String resolution;
        private String peripheral;

        public Builder(String cpu, String screen) {
            this.cpu = cpu;
            this.screen = screen;
        }

        public Builder setGpu(String gpu){
            this.gpu = gpu;
            return this;
        }

        public Builder setResolution(String resolution){
            this.resolution = resolution;
            return this;
        }

        public Builder setPeripheral(String peripheral){
            this.peripheral = peripheral;
            return this;
        }

        public MiTV5 build(){
            return new MiTV5(this);
        }
    }



    @Override
    public String toString() {
        return "MiTV5{" +
                "cpu='" + cpu + '\'' +
                ", screen='" + screen + '\'' +
                ", gpu='" + gpu + '\'' +
                ", resolution='" + resolution + '\'' +
                ", peripheral='" + peripheral + '\'' +
                '}';
    }

    public static void main(String[] args) {
        MiTV5 miTV5 = new Builder("A53_4核", "65寸")
                .setGpu("MEMC运动补偿")
                .setResolution("RGB3色真4K")
                .setPeripheral("赠送游戏手柄")
                .build();
        System.out.println(miTV5.toString());
    }
}

 

原型模式

原型模式(对象深拷贝):直接拷贝已经存在于内存的实例对象,生成新的实例。适用于需要大量同一类对象的场景,直接拷贝的效率要高于new创建的效率;此外,实例对象的成员属性大部分相同,只有少量属性需要更改,使用拷贝可以减少赋值工作。(关于拷贝的知识,如果有所淡忘,可以查阅《Java基础篇--拷贝》)

/**
 * 拷贝就是原型模式
 */
public class Resume implements Cloneable {
    private String name;
    private String selfEvaluation;
    private String salary;

    public Resume(String name, String selfEvaluation, String salary) {
        this.name = name;
        this.selfEvaluation = selfEvaluation;
        this.salary = salary;
    }

    @Override
    public Resume clone() throws CloneNotSupportedException {
        return (Resume) super.clone();
    }

    public void setSalary(String salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Resume:{name:'"+name+"',selfEvaluation:'"+selfEvaluation
                +"',salary:'"+salary+"'}";
    }

    public static void main(String[] args) {
        Resume resumeMuban = new Resume("张三"
                , "5年后台深耕经验,熟悉各大后台框架,精通java,熟练使用各大组件,玩转微服务"
                , "20K");
        try {
            Resume resume1 = resumeMuban.clone();
            resume1.setSalary("21K");
            Resume resume2 = resumeMuban.clone();
            resume2.setSalary("18k");
            Resume resume3 = resumeMuban.clone();
            resume3.setSalary("19K");
            System.out.println(resume1);
            System.out.println(resume2);
            System.out.println(resume3);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

 

结构型模式

结构型模式:组合、封装、装饰类和对象,形成更丰富的用例。旨在复用类、扩展类、代理类等对已有类进行增强。

适配器模式

某一类设计的方法已经不再适应新的系统,但我们又想继续使用这个类的方法作为底层实现,此时就需要一个适配器,实现对这个类的包装。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。使用适配器模式的优点:不需要修改或者废弃原有的功能类,只需要增加一个适配器类,就可以继续让原有的功能类工作,加强了代码复用,且遵循开闭原则。比如:有一根Usb线,但是现在手机升级了,变成了TypeC接口,此时就需要一个转换头,让我们可以继续使用Usb线充电。

public class Usb {
    public void usbOutput(){
        System.out.println("usb输出");
    }
}

public interface Usb2TypeC {
    void output();
}

/**
 * 适配器模式
 * 类适配器:子类继承父类,可以直接调用父类方法
 * 对象适配器:持有对象实例,通过对象实例调用对象成员方法
 */
/*
public class UsbTypeCAdapter extends Usb implements Usb2TypeC {

    @Override
    public void output() {
        super.usbOutput();
    }
}
*/

public class UsbTypeCAdapter implements Usb2TypeC {

    private Usb usb = new Usb();

    @Override
    public void output() {
        usb.usbOutput();
    }
}

 

桥接模式

桥接模式:将两个维度桥接起来,两个维度可以独立变化,互不影响。桥接模式可以有效避免多层继承,尽量遵循单一原则,极大的提供系统可扩展性。

实例:电脑销售,我们常规想到的是建立一个抽象类computer,含有电脑的常规属性和基本功能,设计抽象方法以供子类具体扩展。随着市场发展,衍生出诸多品牌,此时我们只能是继续创建诸多的品牌子类继承computer,然后整个继承链都被修改,导致层级越来越多,越来越难以维护。采用桥接模式设计,可以尽量分离出多个抽象类,降低继承的层级,便于系统扩展。将品牌拆开来,brand和computer两个顶层父类,缩短继承链;而且各自都可以很方便的扩展,互不影响。

public abstract class Brand {
    public String name;

    public Brand(String name) {
        this.name = name;
    }

    public abstract void show();
}


public class Dell extends Brand {

    public Dell() {
        super("戴尔");
    }

    @Override
    public void show() {
        System.out.println("品牌:"+name);
    }
}

public class Lenovo extends Brand {

    public Lenovo() {
        super("联想");
    }

    @Override
    public void show() {
        System.out.println("品牌:"+name);
    }
}

public abstract class Computer {
    protected Brand brand;

    public Computer(Brand brand) {
        this.brand = brand;
    }

    public void show(){
        brand.show();
    }
}

public class Desktop extends Computer {

    public Desktop(Brand brand) {
        super(brand);
    }

    @Override
    public void show() {
        super.show();
        System.out.println("品种:台式电脑");
    }
}

public class Laptop extends Computer {

    public Laptop(Brand brand) {
        super(brand);
    }

    @Override
    public void show() {
        super.show();
        System.out.println("品种:笔记本");
    }
}

public class Customer {
    public static void main(String[] args) {
        Desktop desktop = new Desktop(new Lenovo());
        desktop.show();
        Laptop laptop = new Laptop(new Dell());
        laptop.show();
    }
}

 

组合模式

组合模式(Composite Pattern)将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户可以使用一致的方法操作单个对象和组合对象。

比如:安徽大学拥有两个校区,磬苑校区和龙河校区,每个校区都有各自的学院,共同组成了安徽大学。

public abstract class College {
    private String name;
    public College(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

public class EnglishCollege extends College {
    public EnglishCollege() {
        super("英语学院");
    }
}

public class SoftwareCollege extends College {
    public SoftwareCollege() {
        super("软件学院");
    }
}

public class MathCollege extends College {
    public MathCollege() {
        super("数学学院");
    }
}

public class InternationalCollege extends College {
    public InternationalCollege() {
        super("国际学院");
    }
}

public abstract class Campus {
    protected List<College> collegeList = new LinkedList<>();
    public void addCollege(College college){
        collegeList.add(college);
    }
    public void removeCollege(College college){
        collegeList.remove(college);
    }
    public abstract void show();
}

public class QinyuanCampus extends Campus {
    public QinyuanCampus() {
        addCollege(new SoftwareCollege());
        addCollege(new EnglishCollege());
        addCollege(new MathCollege());
    }

    @Override
    public void show() {
        for (College college : collegeList) {
            System.out.println("磬苑校区:"+college.getName());
        }
    }
}

public class LongheCampus extends Campus {
    public LongheCampus() {
        addCollege(new EnglishCollege());
        addCollege(new InternationalCollege());
    }

    @Override
    public void show() {
        for (College college : collegeList) {
            System.out.println("龙河校区:"+college.getName());
        }
    }
}

public class AnHuiUniversity {
    private List<Campus> campusList = new LinkedList<>();

    public void addCampus(Campus campus){
        campusList.add(campus);
    }

    public void removeCampus(Campus campus){
        campusList.remove(campus);
    }
    
    public void show(){
        for (Campus campus : campusList) {
            campus.show();
        }
    }

    public static void main(String[] args) {
        AnHuiUniversity anHuiUniversity = new AnHuiUniversity();
        anHuiUniversity.addCampus(new QinyuanCampus());
        anHuiUniversity.addCampus(new LongheCampus());
        anHuiUniversity.show();
    }
}

 

装饰模式

装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更灵活。

public class Apple {
    public void showAppearance(){
        System.out.print("裸苹果");
    }
}

public abstract class Decrator extends Apple {
    private Apple apple;

    public Decrator(Apple apple) {
        this.apple = apple;
    }

    @Override
    public void showAppearance() {
        if (null != apple){
            apple.showAppearance();
        }
    }
}

public class FoxconnDecrator extends Decrator {

    public FoxconnDecrator(Apple apple) {
        super(apple);
    }

    @Override
    public void showAppearance() {
        System.out.print("给‘");
        super.showAppearance();
        System.out.println("’贴上红富士标签");
    }
}

public class YantaiDecrator extends Decrator {
    public YantaiDecrator(Apple apple) {
        super(apple);
    }

    @Override
    public void showAppearance() {
        System.out.print("给‘");
        super.showAppearance();
        System.out.println("’贴上山东烟台标签");
    }
}

public class Test {
    public static void main(String[] args) {
        FoxconnDecrator foxconnDecrator = new FoxconnDecrator(new Apple());
        foxconnDecrator.showAppearance();
        YantaiDecrator yantaiDecrator = new YantaiDecrator(new Apple());
        yantaiDecrator.showAppearance();
    }
}

装饰者模式就是对被装饰者进行增强,比如上例对apple进行增强,多个不同的装饰,就是多个装饰者子类。

 

外观模式

外观模式(Facade),为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。隐藏底层细节,需要什么功能只能通过门面接口开通,更加安全。

public class Lays {
    public void sale(){
        System.out.println("乐事做活动,买三送一");
    }
}

public class Yogurt {
    public void update(){
        System.out.println("君乐宝上新啦,全新芝士口味系列酸奶:芝士霉霉、芝士厚烧、芝士海盐");
    }
}

public class Facade {
    private Lays lays;
    private Yogurt yogurt;

    public Facade(Lays lays, Yogurt yogurt) {
        this.lays = lays;
        this.yogurt = yogurt;
    }

    public void saleLays(){
        lays.sale();
    }

    public void updateYogurt(){
        yogurt.update();
    }

    public static void main(String[] args) {
        Facade facade = new Facade(new Lays(), new Yogurt());
        facade.saleLays();
        facade.updateYogurt();
    }
}

 

亨元模式

亨元模式:运用共享技术有效地支持大量细粒度的对象,池技术的重要实现方式。享元模式可以分成单纯享元模式复合享元模式两种形式,享元模式可以分成单纯享元模式复合享元模式两种形式。

单纯享元模式所涉及到的角色如下:

  ●  抽象享元(Flyweight)角色 :给出一个抽象接口,以规定出所有具体享元角色需要实现的方法。

  ●  具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定出的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。

  ●  享元工厂(FlyweightFactory)角色 :本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个符合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。

复合亨元模式相较于单纯亨元模式,增加了一个复合亨元角色,然后在工厂类中增加了一个获取复合亨元角色的方法。

public interface Flyweight {
    //一个示意性方法,参数state是外蕴状态
    public void operation(String state);
}

public class ConcreteFlyweight implements Flyweight {
    private Character intrinsicState = null;
    /**
     * 构造函数,内蕴状态作为参数传入
     * @param state
     */
    public ConcreteFlyweight(Character state){
        this.intrinsicState = state;
    }
    
    
    /**
     * 外蕴状态作为参数传入方法中,改变方法的行为,
     * 但是并不改变对象的内蕴状态。
     */
    @Override
    public void operation(String state) {
        System.out.println("Intrinsic State = " + this.intrinsicState);
        System.out.println("Extrinsic State = " + state);
    }
}

public class FlyweightFactory {
    private Map<Character,Flyweight> files = new HashMap<Character,Flyweight>();
    
    public Flyweight factory(Character state){
        //先从缓存中查找对象
        Flyweight fly = files.get(state);
        if(fly == null){
            //如果对象不存在则创建一个新的Flyweight对象
            fly = new ConcreteFlyweight(state);
            //把这个新的Flyweight对象添加到缓存中
            files.put(state, fly);
        }
        return fly;
    }
}

public class Client {

    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight fly = factory.factory(new Character('a'));
        fly.operation("First Call");
        
        fly = factory.factory(new Character('b'));
        fly.operation("Second Call");
        
        fly = factory.factory(new Character('a'));
        fly.operation("Third Call");
    }
}

 

代理模式

代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用,对原对象进行增强。通俗的来讲代理模式就是我们生活中常见的中介。Java中常见的有三种代理模式:静态代理、动态代理——依赖jdk的api实现和依赖cglib实现。

静态代理:实现具体子类,增强被代理对象。

public interface Lenovo {
    String sale(double price);
    String show();
}

public class LenovoHome implements Lenovo {
    @Override
    public String sale(double price) {
        return String.format("花了%s元在联想原厂买了一台Lenovo电脑",price);
    }

    @Override
    public String show() {
        return "展示电脑:性能超强,显存极大,固态,液冷!!!";
    }
}

public class HefeiLenovo implements Lenovo {

    private LenovoHome lenovoHome;

    public HefeiLenovo(LenovoHome lenovoHome) {
        this.lenovoHome = lenovoHome;
    }

    @Override
    public String sale(double price) {
        System.out.println("合肥代理店进货,"+lenovoHome.sale(price*0.85));
        return String.format("客户实际花了%s元在合肥联想代理店买了一台电脑",price);
    }

    @Override
    public String show() {
        return "展示电脑:性能超强,显存极大,固态,液冷!!!外送原厂鼠标,键盘";
    }
}

动态代理:基于JDK Api实现(基于接口的动态代理)

    /**
     * 基于接口的动态代理(基于子类的动态代理需要依赖jar包cglib实现)
     * 动态代理:动态代理,内存中是没有具体的代理类,而是在具体执行时动态生成的
     * 利用Proxy.newProxyInstance静态方法得到动态代理对象
     * 在invoke中可以对具体的方法进行增强
     * 1.对参数增强:获取到参数,对参数进行处理之后,再作为执行方法的入参
     * 2.对方法体增强:在实体类执行方法前后,可以添加想要执行的逻辑
     * 3.对返回值增强:在实体类方法执行后,获取到返回值,进行处理之后,再返回给调用者
     *
     * 使用动态代理对象执行方法,此时就会得到增强后的结果
     */
    public static void testDynamicProxy(){
        Lenovo lenovo = new LenovoHome();
        Lenovo proxy_lenovo = (Lenovo) Proxy.newProxyInstance(LenovoHome.class.getClassLoader(), LenovoHome.class.getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (method.getName().equals("sale")){
                    //对sale方法进行增强
                    double price = (double) args[0]*1.25;//对参数增强
                    System.out.println("专车接送,直达店面");//对方法体增强
                    Object result = method.invoke(lenovo, price);//使用lenovohome对象执行具体方法,参数已经被改变
                    System.out.println("免费送货到家");//对方法体增强
                    return result+",免费赠送原厂鼠标+键盘";//对返回值增强
                } else {
                    Object invoke = method.invoke(lenovo, args);
                    return invoke;
                }
            }
        });

        String sale = proxy_lenovo.sale(8000);
        System.out.println(sale);
        System.out.println(proxy_lenovo.show());
    }

动态代理:基于cglib库实现(基于子类的动态代理),需要依赖cglib jar(spring-core 3.2版本之后,就引入了cglib,所以maven项目可以直接引入spring-core依赖即可)

public class Lenovo {
    public String sale(double price){
        return "花了"+price+"元买了一台电脑";
    }

    public String show(){
        return "展示电脑:性能超强,显存极大,固态,液冷!!!";
    }
}

public class ProxyFactory implements MethodInterceptor {

    //被代理对象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    //给被代理对象创建一个代理
    public Object getProxyInstance(){
        //工具类
        Enhancer enhancer = new Enhancer();
        //设置被代理父类
        enhancer.setSuperclass(target.getClass());
        //设置回调
        enhancer.setCallback(this);
        //创建代理
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if (method.getName().equals("sale")){
            //对sale方法进行增强
            double price = (double) objects[0]*1.25;//对参数增强
            System.out.println("专车接送,直达店面");//对方法体增强
            Object result = method.invoke(target, price);//使用target对象执行具体方法,参数已经被改变
            System.out.println("免费送货到家");//对方法体增强
            return result+",免费赠送原厂鼠标+键盘";//对返回值增强
        } else {
            Object invoke = method.invoke(target, objects);
            return invoke;
        }
    }
}

public class Customer {
    public static void main(String[] args) {
        Lenovo lenovo = new Lenovo();
        Lenovo proxy = (Lenovo) new ProxyFactory(lenovo).getProxyInstance();
        System.out.println(proxy.sale(8000));
        System.out.println(proxy.show());
    }
}

 

行为型模式:

用来识别对象之间的常用交流模式并加以实现,如此,可在进行这些交流活动时增强弹性。

访问者模式

访问者模式是一种将数据操作和数据结构分离的设计模式。

// 员工基类
public abstract class Staff {

    public String name;
    public int kpi;// 员工KPI

    public Staff(String name) {
        this.name = name;
        kpi = new Random().nextInt(10);
    }
    // 核心方法,接受Visitor的访问
    public abstract void accept(Visitor visitor);
}

// 工程师
public class Engineer extends Staff {

    public Engineer(String name) {
        super(name);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    // 工程师一年的代码数量
    public int getCodeLines() {
        return new Random().nextInt(10 * 10000);
    }
}

// 经理
public class Manager extends Staff {

    public Manager(String name) {
        super(name);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    // 一年做的产品数量
    public int getProducts() {
        return new Random().nextInt(10);
    }
}

public interface Visitor {

    // 访问工程师类型
    void visit(Engineer engineer);

    // 访问经理类型
    void visit(Manager manager);
}

// CEO访问者
public class CEOVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程师: " + engineer.name + ", KPI: " + engineer.kpi);
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("经理: " + manager.name + ", KPI: " + manager.kpi +
                ", 新产品数量: " + manager.getProducts());
    }
}

public class CTOVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程师: " + engineer.name + ", 代码行数: " + engineer.getCodeLines());
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("经理: " + manager.name + ", 产品数量: " + manager.getProducts());
    }
}

// 员工业务报表类
public class BusinessReport {

    private List<Staff> mStaffs = new LinkedList<>();

    public BusinessReport() {
        mStaffs.add(new Manager("经理-A"));
        mStaffs.add(new Engineer("工程师-A"));
        mStaffs.add(new Engineer("工程师-B"));
        mStaffs.add(new Engineer("工程师-C"));
        mStaffs.add(new Manager("经理-B"));
        mStaffs.add(new Engineer("工程师-D"));
    }

    /**
     * 为访问者展示报表
     * @param visitor 公司高层,如CEO、CTO
     */
    public void showReport(Visitor visitor) {
        for (Staff staff : mStaffs) {
            staff.accept(visitor);
        }
    }
}

public class Client {

    public static void main(String[] args) {
        // 构建报表
        BusinessReport report = new BusinessReport();
        System.out.println("=========== CEO看报表 ===========");
        report.showReport(new CEOVisitor());
        System.out.println("=========== CTO看报表 ===========");
        report.showReport(new CTOVisitor());
    }
}

如上例:某公司年底计算绩效,主要由CEO和CTO来确定,员工主要有两类:工程师、产品经理。其中CEO主要关注工程师的KPI以及产品经理kpi和新产品数量,CTO主要关注工程师的代码量以及产品经理的新产品数量。用访问者模式设计:员工抽象类(staff,定义核心方法accept(Visitor)),具体的员工类继承员工抽象类(工程师:Enginner,产品经理:Manager);员工类相当于数据结构,用一个accept(Visitor)方法分离数据操作,具体的数据操作放到Visitor中去。访问者接口类:Visitor(定义visit方法),具体的访问者实现类实现Visitor接口(CEOVisitor和CTOVisitor),在具体的访问者类中实现具体的数据操作逻辑。统一的数据集合——报表类(BusinessReport),持有数据集,以及提供遍历操作数据的入口。

 

模板模式

 定义一个操作中算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。

/**
 * 项目模板
 * 定义做项目的方法:规定具体步骤和顺序
 * 步骤的具体实现交给具体项目实体类
 */
public abstract class ProjectTemplate {

    //做项目主要有三个步骤:数据库设计、框架设计、编码
    public void doProject(){
        this.doDataBaseDesign();
        this.doFrameworkDesign();
        this.doEncoding();
    }

    public abstract void doDataBaseDesign();

    public abstract void doFrameworkDesign();

    public abstract void doEncoding();
}

public class UserManagerProject extends ProjectTemplate {
    @Override
    public void doDataBaseDesign() {
        System.out.println("设计用户管理系统数据库");
    }

    @Override
    public void doFrameworkDesign() {
        System.out.println("进行用户管理系统框架设计");
    }

    @Override
    public void doEncoding() {
        System.out.println("编码实现用户管理系统");
    }
}

public class SpeechRecognizeProject extends ProjectTemplate {
    @Override
    public void doDataBaseDesign() {
        System.out.println("设计语音识别系统的数据库");
    }

    @Override
    public void doFrameworkDesign() {
        System.out.println("进行语音识别系统框架设计");
    }

    @Override
    public void doEncoding() {
        System.out.println("语音识别系统编码实现");
    }
}

public class DevelopmentGroup {

    public static void main(String[] args) {
        System.out.println("----------------研发团队做的第一个项目");
        ProjectTemplate project = new UserManagerProject();
        project.doProject();

        System.out.println("----------------研发团队做的第二个项目");
        ProjectTemplate project2 = new SpeechRecognizeProject();
        project2.doProject();
    }
}

 

策略模式

定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。

public abstract class Strategy {
    public abstract void operate();
}

public class StrategyA extends Strategy {
    @Override
    public void operate() {
        System.out.println("A策略具体操作");
    }
}

public class StrategyB extends Strategy {
    @Override
    public void operate() {
        System.out.println("B策略具体操作");
    }
}


public class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public void contextDo(){
        strategy.operate();
    }
}

public class Test {
    public static void main(String[] args) {
        Context context = new Context(new StrategyA());
        context.contextDo();

        Context context1 = new Context(new StrategyB());
        context1.contextDo();
    }
}

 

状态模式

当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。

public abstract class State {

    public abstract void Handle(Context context);
}

public class ConcreteStateA extends State{
    @Override
    public void Handle(Context context) {
        context.setState(new ConcreteStateB()); //设置A的下一个状态是B
    }
}

public class ConcreteStateB extends State{
    @Override
    public void Handle(Context context) {
        context.setState(new ConcreteStateA()); //设置B的下一个状态是A
    }
}

public class Context {
    State state;
 
    public Context(State state) { //定义Context的初始状态
        super();
        this.state = state;
    }
 
    public State getState() {
        return state;
    }
 
    public void setState(State state) {
        this.state = state;
        System.out.println("当前状态为"+state);
    }
    public void request(){
        state.Handle(this); //对请求做处理并且指向下一个状态
    }
}

public class Test {
    public static void main(String[] args) {
        Context context = new Context(new ConcreteStateA());
        System.out.println(context.getState());
        context.request();
    }
}

上例是不是很像工作流系统。

 

观察者模式

观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。

模拟炒股:一只股票Stock,一个股民Investor购买该股票,并订阅关注该股票涨跌;股票发生大幅涨跌时,就会自动通知股民。

public abstract class Subject {
    private CopyOnWriteArrayList<Observer> observerList = new CopyOnWriteArrayList<>();

    public void registor(Observer observer){
        observerList.add(observer);
    }

    public void cancel(Observer observer){
        observerList.remove(observer);
    }

    public void notifyObservers(){
        for (Observer observer : observerList) {
            observer.update();
        }
    }
}

public class Stock extends Subject {
    private double increase = 0.0;

    public double getIncrease(){
        return increase;
    }

    public void change(){
        double now = new Random().nextDouble();
        double limit = now - increase;
        if (limit > 0.3 || limit < -0.3){
            increase = limit;
            notifyObservers();
        }
    }
}

public interface Observer {
    void update();
}

public class Investor implements Observer {

    private Stock stock;

    public Investor(Stock stock) {
        this.stock = stock;
        stock.registor(this::update);
    }

    @Override
    public void update() {
        double increase = stock.getIncrease();
        if (increase > 0){
            System.out.println("哈哈,股票大涨啊,涨幅:"+increase);
        } else {
            System.out.println("完了,倾家荡产了,我要去天台,别拦我!"+increase);
        }
    }
}

public class SpeculateStocks {
    public static void main(String[] args) throws InterruptedException {
        //生成一只股票
        Stock stock = new Stock();
        //模拟一个股民购买了该股票,并时刻关注股票的涨跌情况
        new Investor(stock);
        while (true){
            //模拟每天股票涨跌
            stock.change();
            Thread.sleep(40);
        }

    }
}

 

备忘录模式

备忘录模式(Memento),在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存着这个状态。这样以后就可将该对象恢复到原先保存的状态。

备忘录模式主要有三个角色:发起人Originator,负责发起一个初始状态的事务以及基于自身状态创建备忘录;备忘录Memento,负责记录事务的状态;备忘录管理者Creataker,负责存储备忘录。

public class Originator {

    private String state;

    public void setState(String state) {
        this.state = state;
    }

    public Memento createMento() {
        return (new Memento(state));
    }

    public void setMemento(Memento memento) {
        this.state = memento.getState();
    }

    public void show() {
        System.out.println("state = " + state);
    }

}

public class Memento {

    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

}

public class Caretaker {

    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }

}

public class Client {

    public static void main(String[] args) {
        //发起人设置初始状态
        Originator originator = new Originator();
        originator.setState("On");    //Originator初始状态
        originator.show();

        //备忘录管理者保存发起人基于自身此刻状态创建的备忘录
        Caretaker caretaker = new Caretaker();
        caretaker.setMemento(originator.createMento());

        //发起人改变状态
        originator.setState("Off");    //Originator状态变为Off
        originator.show();

        //发起人通过备忘录管理者保存的备忘录恢复自身的状态
        originator.setMemento(caretaker.getMemento());    //回复初始状态
        originator.show();
    }

}

 

中介者模式

同事类之间相互耦合,相互影响,为了可减少耦合,分开这种影响,所以引入了中介者模式。同事类就是互相持有对方,并且当自身发生变化时会影响对方也随着改变的类。

中介者模式是一种比较常用的模式,也是一种比较容易被滥用的模式。对于大多数的情况,同事类之间的关系不会复杂到混乱不堪的网状结构,因此,大多数情况下,将对象间的依赖关系封装的同事类内部就可以的,没有必要非引入中介者模式。

举例:当一个同事类A改变时,同事类B也跟着改变;同事类B改变时同事类A也随之改变。此时如果不使用中介者模式,那就是A和B互相持有对方实例,在自身改变时,通过对方的实例引用来改变对方,存在着严重的耦合。引入中介者模式,则可以消除耦合,A和B所有的改变都由中介者来操作。

public abstract class Colleagues {
    protected int number;

    public abstract void change(int number,Mediator mediator);
}

public class ColleaguesA extends Colleagues{

    @Override
    public void change(int number,Mediator mediator) {
        this.number = number;
        mediator.AModifyB();
    }
}

public class ColleaguesB extends Colleagues {
    @Override
    public void change(int number, Mediator mediator) {
        this.number = number;
        mediator.BModifyA();
    }
}

public abstract class Mediator {

    protected Colleagues colleaguesA;
    protected Colleagues colleaguesB;

    public Mediator(Colleagues colleaguesA, Colleagues colleaguesB) {
        this.colleaguesA = colleaguesA;
        this.colleaguesB = colleaguesB;
    }

    public abstract void AModifyB();

    public abstract void BModifyA();
}

public class ABMediator extends Mediator {
    public ABMediator(Colleagues colleaguesA, Colleagues colleaguesB) {
        super(colleaguesA, colleaguesB);
    }

    @Override
    public void AModifyB() {
        colleaguesB.number = colleaguesA.number*100;
        System.out.println("A:"+colleaguesA.number+",B:"+colleaguesB.number);
    }

    @Override
    public void BModifyA() {
        colleaguesA.number = colleaguesB.number/100;
        System.out.println("B:"+colleaguesB.number+",A:"+colleaguesA.number);
    }
}

public class Test {
    public static void main(String[] args) {
        Colleagues A = new ColleaguesA();
        Colleagues B = new ColleaguesB();
        ABMediator abMediator = new ABMediator(A, B);
        A.change(10,abMediator);
        System.out.println("---------------");
        B.change(2000,abMediator);
    }
}

 

迭代器模式

迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。集合中常用的遍历就是通过迭代器实现。Java为迭代器模式还建立了迭代器接口。

public class MenuItem {

    private String name;
    private double price;

    public MenuItem(String name, double price) {
        this.name = name;
        this.price = price;
    }
    
    @Override
    public String toString() {
        return "MenuItem{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

public interface Menu {
    Iterator<MenuItem> createIterator();
}

public class KFCMenu implements Menu {
    private List<MenuItem> menuItems = new ArrayList<>();

    public KFCMenu() {
        menuItems.add(new MenuItem("烤翅",9.8));
        menuItems.add(new MenuItem("薯条",7.9));
        menuItems.add(new MenuItem("汉堡",8.5));
        menuItems.add(new MenuItem("可乐",5.6));
        menuItems.add(new MenuItem("上校鸡块",6.3));
    }

    @Override
    public Iterator<MenuItem> createIterator() {
        return new KFCMenuIterator(menuItems);
    }
}

public class KFCMenuIterator implements Iterator<MenuItem> {
    private List<MenuItem> menuItems;
    private int position = 0;

    public KFCMenuIterator(List<MenuItem> menuItems) {
        this.menuItems = menuItems;
    }

    @Override
    public boolean hasNext() {
        if (position < menuItems.size()){
            return true;
        }
        return false;
    }

    @Override
    public MenuItem next() {
        return menuItems.get(position++);
    }
}

public class Customer {
    public static void main(String[] args) {
        KFCMenu kfcMenu = new KFCMenu();
        Iterator<MenuItem> iterator = kfcMenu.createIterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next().toString());
        }
    }
}

 

解释器模式

解释器模式:给定一个语言,定义它的文法得一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

比如本例:输入“down run 10”,经过解释器执行后,转换为“向下奔跑10”。

public abstract class AbstractNode {
	public abstract String interpret();
}

public class DirectionNode extends AbstractNode {
	private String direction;
	public DirectionNode(String dir) {
		this.direction=dir;
	}
	@Override
	public String interpret() {
		if(direction.equalsIgnoreCase("up")) {
			return "向上";
		}else if(direction.equalsIgnoreCase("down")) {
			return "向下";
		}else if(direction.equalsIgnoreCase("left")) {
			return "向左";
		}else if(direction.equalsIgnoreCase("right")) {
			return "向右";
		}else {
			return "无效指令";
		}
	}
}

public class ActionNode extends AbstractNode {
	private String action;
	public ActionNode(String a) {
		this.action=a;
	}
	@Override
	public String interpret() {
		if(action.equalsIgnoreCase("move")) {
			return "移动";
		}else if(action.equalsIgnoreCase("run")) {
			return "奔跑";
		}else {
		return "无效指令";
		}
	}
}

public class DistanceNode  extends AbstractNode{
	private String distance;
	public DistanceNode(String d) {
		this.distance=d;
	}
	@Override
	public String interpret() {
		return distance;
	}
}

public class SentenceNode extends AbstractNode{
	private AbstractNode direction;
	private AbstractNode action;
	private AbstractNode distanc;
 
	public SentenceNode(AbstractNode direc,AbstractNode a,AbstractNode d) {
		this.direction=direc;
		this.action=a;
		this.distanc=d;
	}
	@Override
	public String interpret() {
		return direction.interpret()+action.interpret()+distanc.interpret();
	}
}

public class InstructionHandler {
	private AbstractNode node;

	public void Handle(String instruction) {
		//用栈来保存语法树。
		AbstractNode left=null;
		AbstractNode direction=null,action=null,distance=null;
		Stack<AbstractNode> stack = new Stack<AbstractNode>();
		
		//用空格分隔指令
		String[] word = instruction.split(" ");
		//循环
		for(int i=0;i<word.length;i++) {
			String word1 = word[i];
			direction = new DirectionNode(word1);
			String word2 = word[++i];
			action = new ActionNode(word2);
			String word3 = word[++i];
			distance = new DistanceNode(word3);
			left= new SentenceNode(direction, action, distance);
			stack.push(left);
		}
		this.node=(AbstractNode)stack.pop();
	}
	
	public String output() {
		String result = node.interpret();
		return result;
	}
}

public class Client {
	public static void main(String[] args) {
		String instruction ="down run 10";
		InstructionHandler iHandler = new InstructionHandler();
		iHandler.Handle(instruction);
		String outString =iHandler.output();
		System.out.println(outString);
	}
}

 

命令模式

命令模式设计模式属于行为型模式,将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

举例:一个拥有十个可编程按钮的遥控器,每个按钮可以设定一个具体的动作,且可以撤销执行。我们现在对这个遥控器进行编程,设定0号按钮控制家里的电灯打开,1号按钮控制电灯关闭。

public interface Command {
    void execute();
    void cancel();
}

public class NoCommand implements Command {
    @Override
    public void execute() {}

    @Override
    public void cancel() {}
}

public class LightOn implements Command {
    private LightReceiver lightReceiver;

    public LightOn(LightReceiver lightReceiver) {
        this.lightReceiver = lightReceiver;
    }

    @Override
    public void execute() {
        lightReceiver.on();
    }

    @Override
    public void cancel() {
        lightReceiver.off();
    }
}

public class LightOff implements Command {
    private LightReceiver lightReceiver;

    public LightOff(LightReceiver lightReceiver) {
        this.lightReceiver = lightReceiver;
    }

    @Override
    public void execute() {
        lightReceiver.off();
    }

    @Override
    public void cancel() {
        lightReceiver.on();
    }
}

public class LightReceiver {
    public void on(){
        System.out.println("打开电灯");
    }

    public void off(){
        System.out.println("关闭电灯");
    }
}

public class RemoteController {
    private List<Command> commands = new ArrayList<>(10);

    public RemoteController() {
        for (int i = 0; i < 10; i++) {
            commands.add(new NoCommand());
        }
    }

    public void setCommand(int index,Command command){
        commands.set(index,command);
    }

    public void down(int index){
        commands.get(index).execute();
    }

    public void cancel(int index){
        commands.get(index).cancel();
    }
}

public class User {
    public static void main(String[] args) {
        RemoteController remoteController = new RemoteController();
        LightReceiver lightReceiver = new LightReceiver();
        remoteController.setCommand(0,new LightOn(lightReceiver));
        remoteController.setCommand(1,new LightOff(lightReceiver));

        remoteController.down(1);
        remoteController.down(0);
    }
}

 

责任链模式

责任链模式:使多个对象都有机会处理同一个请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

举例:双十一顾客去商场买东西,申请折扣;销售员能直接批准的是5个点,经理是30个点,CEO是50个点。当顾客向销售员申请折扣的时候,销售员会根据折扣大小去处理,如果在其权限范围内,则直接批准,否则向上级领导提交申请,由领导审批,依次逐级下去,直到有一个人处理了该申请。

public abstract class PriceHandler {
    protected PriceHandler superior;

    public PriceHandler(PriceHandler superior) {
        this.superior = superior;
    }

    public abstract void processDiscount(double discount);
}


public class Salesman extends PriceHandler {

    public Salesman(PriceHandler superior) {
        super(superior);
    }

    @Override
    public void processDiscount(double discount) {
        if (discount < 0.05){
            System.out.format("%s批准了折扣 %.2f\n",this.getClass().getName(),discount);
        } else {
            superior.processDiscount(discount);
        }
    }
}

public class Manager extends PriceHandler {

    public Manager(PriceHandler superior) {
        super(superior);
    }

    @Override
    public void processDiscount(double discount) {
        if (discount <= 0.3){
            System.out.format("%s批准了折扣 %.2f\n",this.getClass().getName(),discount);
        } else {
            superior.processDiscount(discount);
        }
    }
}

public class CEO extends PriceHandler {

    public CEO(PriceHandler superior) {
        super(superior);
    }

    @Override
    public void processDiscount(double discount) {
        if (discount <= 0.5){
            System.out.format("%s批准了折扣 %.2f\n",this.getClass().getName(),discount);
        } else {
            System.out.format("很抱歉,这个%.2f折扣我们做不了",discount);
        }
    }
}

public class Customer {
    public static void main(String[] args) {
        CEO ceo = new CEO(null);
        Manager manager = new Manager(ceo);
        Salesman salesman = new Salesman(manager);
        System.out.println("顾客1向销售员申请7折优惠");
        salesman.processDiscount(0.3);
        System.out.println("顾客2向销售员申请4折优惠");
        salesman.processDiscount(0.6);
    }
}

 

 


以上系个人理解,如果存在错误,欢迎大家指正。原创不易,转载请注明出处!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值