文章目录

  • 一、简单工厂模式&静态工厂模式
  • 二、工厂方法模式
  • 三、抽象工厂模式
  • 四、原型模式
  • 五、单例模式
    • a.饿汉式
    • b.懒汉式
      • 1.第一种实现方式(Gamma Singleton)
      • 2.第二种实现方式(Meyers Singleton 基于静态局部变量)
  • 六、建造者模式(生成器模式)

创建型模式提供了创建对象的机制,旨在提升已有代码的灵活性可复用性

部分插图来自: https://refactoringguru.cn/design-patterns/catalog

一、简单工厂模式&静态工厂模式

简单工厂模式严格来说并不是一种设计模式,而更像是一种编程习惯。简单工厂模式在创建对象时不会对客户端暴露创建逻辑,而是通过使用一个共同的接口来提供新创建的对象。当这个提供对象接口被定义为静态方法时,简单工厂模式也被称为静态工厂模式


简单工厂模式包含如下角色:

  • 抽象产品:定义产品规范,描述产品主要特性和功能,是所有具体产品的基类。
  • 具体产品:实现或者继承抽象产品。
  • 具体工厂:提供了创建产品的方法,调用者通过该方法来获取产品。

简单工厂模式优点:

  1. 封装了创建对象的过程,当一个调用者想创建一个对象时只需要知道其名称就可以了。
  2. 对象创建和业务逻辑被分开,如果要添加新产品只需要修改工厂类,而不需要在原代码中修改。降低了客户代码修改的可能性,在一定程度上增加了代码的可扩展性。

简单工厂模式缺点:增加新产品时需要修改工厂类的代码,违背了开闭原则(对扩展开放,对修改封闭)。

#include <iostream>/* 猫基类 */
class Cat {public:virtual void bark() = 0;virtual ~Cat() = default;
};/* 狸花猫 */
class DragonLi : public Cat {public:void bark() override {std::cout << "DragonLi: meow~" << std::endl;}
};/* 缅因猫 */
class MaineCoon : public Cat {public:void bark() override {std::cout << "MaineCoon: meow~" << std::endl;}
};/* 布偶猫 */
class Ragdoll : public Cat {public:void bark() override {std::cout << "Ragdoll: meow~" << std::endl;}
};/* 静态工厂类 专门用来生产猫咪 */
class SimpleCatFactory {public:static Cat *CreateCat(const std::string &category) {if (category == "DragonLi") {return new DragonLi();} else if (category == "MaineCoon") {return new MaineCoon();} else {return new Ragdoll();}}
};int main() {Cat *dragonLi = SimpleCatFactory::CreateCat("DragonLi");dragonLi->bark();Cat *maineCoon = SimpleCatFactory::CreateCat("MaineCoon");maineCoon->bark();Cat *ragdoll = SimpleCatFactory::CreateCat("Ragdoll");ragdoll->bark();delete dragonLi;delete maineCoon;delete ragdoll;return 0;
}
atreus@MacBook-Pro % clang++ main.cpp -o main -std=c++11
atreus@MacBook-Pro % ./main
DragonLi: meow~
MaineCoon: meow~
Ragdoll: meow~
atreus@MacBook-Pro %

二、工厂方法模式

工厂方法模式是一种创建型设计模式, 其在父类中提供一个创建对象的方法接口, 允许子类决定所要实例化对象的类型。工厂方法模式使一个产品类的实例化延迟到工厂的子类中进行。


工厂方法模式包含如下角色:

  • 抽象产品:定义产品规范,描述产品主要特性和功能,是所有具体产品的基类。
  • 具体产品:实现或者继承抽象产品,由具体工厂来创建,与具体工厂之间一一对应。
  • 抽象工厂:提供了创建产品的接口,调用者通用它访问具体工厂的工厂方法来创建产品。
  • 具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。

工厂方法模式优点:

  1. 用户只需要知道具体工厂的名称就可以得到想要的产品,而无需知道产品的具体创建过程,从而避免了用户和具体产品之间的紧密耦合。
  2. 可以将产品创建代码放在程序的单一位置,从而使得代码更容易维护,满足单一职责原则
  3. 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则

工厂方法模式缺点:每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,增加了系统的复杂度。

#include <iostream>/* 猫基类 */
class Cat {public:virtual void bark() = 0;virtual ~Cat() = default;
};/* 狸花猫 */
class DragonLi : public Cat {public:void bark() override {std::cout << "DragonLi: meow~" << std::endl;}
};/* 缅因猫 */
class MaineCoon : public Cat {public:void bark() override {std::cout << "MaineCoon: meow~" << std::endl;}
};/* 抽象工厂类 */
class CatFactory {public:virtual Cat *CreateCat() = 0;virtual ~CatFactory() = default;
};class DragonLiFactory : public CatFactory {public:Cat *CreateCat() override {return new DragonLi();}
};class MaineCoonFactory : public CatFactory {public:Cat *CreateCat() override {return new MaineCoon();}
};int main() {CatFactory *dragonLiFactory = new DragonLiFactory();Cat *dragonLi = dragonLiFactory->CreateCat();dragonLi->bark();delete dragonLi;delete dragonLiFactory;CatFactory *maineCoonFactory = new MaineCoonFactory();Cat *maineCoon = maineCoonFactory->CreateCat();maineCoon->bark();delete maineCoon;delete maineCoonFactory;return 0;
}
atreus@MacBook-Pro % clang++ main.cpp -o main -std=c++11
atreus@MacBook-Pro % ./main
DragonLi: meow~
MaineCoon: meow~
atreus@MacBook-Pro %

三、抽象工厂模式

抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产某个单一的产品,而抽象工厂模式可生产一系列相关的产品。


抽象工厂模式包含如下角色:

  • 抽象产品:定义产品规范,描述产品主要特性和功能,是所有具体产品的基类。
  • 具体产品:实现或者继承抽象产品,由具体工厂来创建,与具体工厂之间是多对一的关系。
  • 抽象工厂:提供了创建产品的接口,调用者通用它访问具体工厂的工厂方法来创建一系列相关的产品。
  • 具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。

抽象工厂方法模式优点:

  1. 可以确保同一工厂生成的产品相互匹配,比如下例中的美国工厂不会生产出日本战舰。
  2. 可以避免客户端和具体产品代码的耦合。
  3. 基于工厂方法模式改进,同样满足单一职责原则开闭原则

抽象工厂方法模式缺点:代码较为复杂,当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。比如我们在下面代码中添加一个有关驱逐舰的方法,包括抽象工厂在内的工厂类都需要进行修改。

#include <iostream>/* 战列舰基类 */
class Battleship {public:virtual void fire() = 0;virtual ~Battleship() = default;
};/* 巡洋舰基类 */
class Cruiser {public:virtual void fire() = 0;virtual ~Cruiser() = default;
};/* 抽象工厂类 */
class AbstractFactory {public:virtual Battleship *createBattleship() = 0;virtual Cruiser *createCruiser() = 0;virtual ~AbstractFactory() = default;
};/* 衣阿华级战列舰 美国 */
class Iowa : public Battleship {public:void fire() override {std::cout << "Iowa: fire!" << std::endl;}
};/* 得梅因级巡洋舰 美国 */
class DesMoines : public Cruiser {public:void fire() override {std::cout << "DesMoines: fire!" << std::endl;}
};/* 大和级战列舰 日本 */
class Yamato : public Battleship {public:void fire() override {std::cout << "Yamato: fire!" << std::endl;}
};/* 伊吹级巡洋舰 日本 */
class Ibuki : public Cruiser {public:void fire() override {std::cout << "Ibuki: fire!" << std::endl;}
};/* 美国工厂类 */
class AmericanFactory : public AbstractFactory {public:Battleship *createBattleship() override {return new Iowa;}Cruiser *createCruiser() override {return new DesMoines;}
};/* 日本工厂类 */
class JapaneseFactory : public AbstractFactory {public:Battleship *createBattleship() override {return new Yamato;}Cruiser *createCruiser() override {return new Ibuki;}
};int main() {AbstractFactory *americanFactory = new AmericanFactory;Battleship *iowa = americanFactory->createBattleship();iowa->fire();delete iowa;delete americanFactory;AbstractFactory *japaneseFactory = new JapaneseFactory;Cruiser *ibuki = japaneseFactory->createCruiser();ibuki->fire();delete ibuki;delete japaneseFactory;return 0;
}
atreus@MacBook-Pro % clang++ main.cpp -o main -std=c++11
atreus@MacBook-Pro % ./main
Iowa: fire!
Ibuki: fire!
atreus@MacBook-Pro %

四、原型模式

原型模式是一种创建型设计模式, 它用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象, 而又无需使代码依赖它们所属的类(依赖实例化后的对象,不依赖类定义)。


原型模式包含如下角色:

  • 抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。
  • 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
  • 访问类:使用具体原型类中的 clone() 方法来复制新的对象。

原型模式优点:

  1. 可以轻松克隆复杂对象,且无需与它们所属的具体类相耦合。
  2. 可以克隆预生成原型,避免反复运行初始化代码。

原型模式缺点:克隆包含循环引用的复杂对象可能会非常麻烦。

#include <iostream>/* 抽象原型类 */
class Prototype {public:virtual Prototype *clone() = 0;virtual ~Prototype() = default;
};/* 猫咪类 */
class Cat : public Prototype {public:Cat() = default;/* 深拷贝 */Cat *clone() override {return new Cat();}/* 浅拷贝 */// Cat *clone() override {//    return this;// }
};int main() {Cat *oldCat = new Cat();Cat *newCat = oldCat->clone();std::cout << oldCat << std::endl;std::cout << newCat << std::endl;delete oldCat;delete newCat;return 0;
}
atreus@MacBook-Pro % clang++ main.cpp -o main -std=c++11
atreus@MacBook-Pro % ./main
0x60000321c040
0x60000321c050
atreus@MacBook-Pro %

五、单例模式

另见对于单例模式以及静态局部变量的深入理解(C++)。

单例模式只涉及到一个单一的类,该类让你能够保证一个类只有一个实例,并提供一个访问该实例的全局节点。


单例模式包含如下角色:

  • 单例类:创建并维持一个唯一实例的类;
  • 访问类:使用单例类。

单例模式优点:

  1. 保证一个类只有一个实例,这对于线程池和连接池等池化对象很有意义。
  2. 仅需要在首次请求单例对象时对其进行初始化。

单例模式缺点:

  1. 单例模式同时解决了保证一个类只有一个实例为该实例提供一个全局访问节点两个问题, 所以违反了单一职责原则
  2. 该模式在多线程环境下需要进行特殊处理, 避免多个线程多次创建单例对象。

单例设计模式分为两种:

  • 饿汉式:类加载时就会创建该单实例对象。
  • 懒汉式:单实例对象不会在类加载时被创建,而是在首次使用该对象时创建。

a.饿汉式

饿汉模式的优点是线程安全,但它的一个很明显缺点是单例创建后不一定会立即被使用,会造成一定的内存浪费

除此以外,饿汉模式还有一个潜在的问题,那就是如果程序中有多个单例类,它们会面临静态初始化顺序问题,即全局变量会在 main 函数之前初始化完成,但是多个全局变量之间并没有确定的初始化顺序。这在面对嵌套单例时更为明显,外层单例类很有可能先于内层单例类构造,我们在编写代码时也不能假设某个全局变量在另一个全局变量之前初始化完成。

#include <iostream>/* 通过静态变量实现的单例类 */
class Cat {private:/* 让构造函数私有以避免类被实例化 */Cat() = default;/* 类对应的唯一的对象 */static Cat *m_instance;public:/* 实例对象的唯一访问方式 */static Cat *getInstance() {return m_instance;}
};/* 静态成员变量需要类内定义类外初始化 */
Cat *Cat::m_instance = new Cat;int main() {Cat *dragonLi = Cat::getInstance();Cat *ragdoll = Cat::getInstance();std::cout << dragonLi << std::endl;std::cout << ragdoll << std::endl;delete dragonLi;return 0;
}
atreus@MacBook-Pro % clang++ main.cpp -o main -std=c++11
atreus@MacBook-Pro % ./main
0x6000007dc040
0x6000007dc040
atreus@MacBook-Pro %

b.懒汉式

1.第一种实现方式(Gamma Singleton)

#include <iostream>using namespace std;/* 通过静态变量实现的单例类 */
class Cat {private:static Cat *instance; // 单例类对应的唯一的对象/* 让构造函数私有以避免类被实例化 */Cat() {cout << "Cat()" << endl;}public:/* 实例对象的唯一访问方式 */static Cat *getInstance() {// 多线程场景下此处需要加锁instance = (instance == nullptr) ? new Cat : instance;return instance;}~Cat() {cout << "~Cat()" << endl;}
};/* 静态成员变量需要类内定义类外初始化 */
Cat *Cat::instance = nullptr;int main() {Cat *dragonLi = Cat::getInstance();Cat *ragdoll = Cat::getInstance();std::cout << dragonLi << std::endl;std::cout << ragdoll << std::endl;delete dragonLi;// delete ragdoll; // 由于两个猫咪实际上是一个单例 所以会发生内存的重复释放return 0;
}
atreus@MacBook-Pro % clang++ main.cpp -o main -std=c++11
atreus@MacBook-Pro % ./main
Cat()
0x600001044040
0x600001044040
~Cat()
atreus@MacBook-Pro %

这种实现方法主要存在两个问题:

  1. 线程不安全。需要在实例化单例前进行加锁,不然很有可能在前一个线程判空后新建单例前后一个线程完成判空,导致实例化多个单例。
  2. 内存安全也存在一定风险。一方面是可能忘记 delete,内存安全完全托管给了 OS;另一方面在一些特殊的情况下也有可能出现上述的重复释放问题。

对于内存安全的问题,一种解决方案是将单例模式与 RAII 机制结合使用,通过增加一个 RAII 类来保证内存安全;另一种更简洁的解决方法则是基于静态局部变量来实现单例类(Meyers Singleton)。

/* 以 RAII 方式来控制单例 */
class CatStore {public:Cat *m_cat;explicit CatStore(Cat *cat) {m_cat = cat;}~CatStore() {delete m_cat;}Cat *getCat() const {return m_cat;}
};int main() {CatStore catStore(Cat::getInstance());Cat *dragonLi = catStore.getCat();Cat *ragdoll = catStore.getCat();std::cout << dragonLi << std::endl;std::cout << ragdoll << std::endl;return 0;
}

2.第二种实现方式(Meyers Singleton 基于静态局部变量)

#include <iostream>using namespace std;/* 通过静态变量实现的单例类 */
class Cat {private:/* 让构造函数私有以避免类被实例化 */Cat() {cout << "Cat()" << endl;}~Cat() {cout << "~Cat()" << endl;}public:/* 实例对象的唯一访问方式 */static Cat *getInstance() {static Cat instance; // 静态成员函数里的静态局部变量等效于类的静态成员变量return &instance;}
};int main() {{Cat *dragonLi = Cat::getInstance();std::cout << dragonLi << std::endl;}Cat *ragdoll = Cat::getInstance();std::cout << ragdoll << std::endl;
}
atreus@MacBook-Pro % clang++ main.cpp -o main -std=c++11
atreus@MacBook-Pro % ./main
Cat()
0x100e10000
0x100e10000
~Cat()
atreus@MacBook-Pro %

首先,对于静态局部变量来说,static 关键字并没有改变它的局部作用域,当定义它的函数或者语句块结束时(如上图中的大括号结束),作用域也随之结束。

但是当静态局部变量离开作用域后,它并没有销毁,仍然驻留在内存当中,只是暂时无法被访问,只要我们再次调用 getInstance() 方法,就能重新得到这个静态局部变量

当程序结束时,该静态局部变量的内存会被自动释放,单例类也会被自动析构,因此内存安全得以保证,上面主函数的执行结果也印证了这一点。

其次,对于线程安全的问题,GCC 等编译器已经支持了静态变量构造和析构函数的多线程安全。以构造函数为例,对于局部静态变量,多线程调用时,首先构造静态变量的线程先加锁,其他线程等锁,因此线程安全也得以保证。

实际上,静态局部变量的多线程安全是与编译选项 -fno-threadsafe-statics 直接挂钩的,而此选项在不同编译器中都默认打开。

六、建造者模式(生成器模式)

生成器模式将一个复杂对象的构建与表示分离,使你能够分步骤创建复杂对象。该模式允许你使用相同的创建代码生成不同类型和形式的对象。


建造者模式包含如下角色:

  • 抽象建造者类:此接口声明了在所有类型建造者中通用的产品构造步骤。
  • 具体建造者类:实现建造者接口,提供构造过程的不同实现,并在构造过程完成后,提供产品的实例。
  • 产品类:要创建的复杂对象。
  • 指挥者类:调用具体建造者来创建复杂对象的各个部分,不涉及具体产品的信息,只负责保证对象各部分完整地按照某种顺序创建。

建造者模式的优点:

  1. 生成不同形式的产品时,可以复用相同的制造代码。
  2. 可以分步创建对象,暂缓创建步骤或递归运行创建步骤。
  3. 可以将复杂构造代码从产品的业务逻辑中分离出来,符合单一职责原则
  4. 如果有新的需求,通过实现一个新的建造者类就可以完成,基本上不用修改之前已经测试通过的代码,容易进行扩展,符合开闭原则

建造者模式的缺点:

  1. 造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制
  2. 由于该模式需要新增多个类,因此代码整体复杂程度会有所增加。
#include <iostream>
#include <string>using namespace std;/* 产品类 */
class Cat {private:string m_leg; // 腿string m_tail; // 尾巴public:const string &getLeg() const {return m_leg;}void setLeg(const string &leg) {m_leg = leg;}const string &getTail() const {return m_tail;}void setTail(const string &tail) {m_tail = tail;}
};/* 抽象建造者 */
class Builder {protected:Cat *m_cat = new Cat();public:virtual void buildLeg() = 0;virtual void buildTail() = 0;virtual Cat *createCat() = 0;virtual ~Builder() {delete m_cat;}
};/* 具体构建者 */
class DragonLiBuilder : public Builder {public:void buildLeg() override {m_cat->setLeg("狸");}void buildTail() override {m_cat->setTail("花");}Cat *createCat() override {return m_cat;}
};/* 具体构建者 */
class RagdollBuilder : public Builder {public:void buildLeg() override {m_cat->setLeg("布");}void buildTail() override {m_cat->setTail("偶");}Cat *createCat() override {return m_cat;}
};/* 指挥者 */
class Director {private:Builder *m_builder;public:explicit Director(Builder *builder) {m_builder = builder;}Cat *construct() {m_builder->buildLeg();m_builder->buildTail();return m_builder->createCat();}~Director() {delete m_builder;}
};int main() {Director dragonLiDirector(new DragonLiBuilder);Cat *dragonLi = dragonLiDirector.construct();cout << dragonLi->getLeg() << dragonLi->getTail() << endl;Director ragdollDirector(new RagdollBuilder);Cat *ragdoll = ragdollDirector.construct();cout << ragdoll->getLeg() << ragdoll->getTail() << endl;return 0;
}
atreus@MacBook-Pro % clang++ main.cpp -o main -std=c++11
atreus@MacBook-Pro % ./main
狸花
布偶
atreus@MacBook-Pro %

创建型设计模式(C++)相关推荐

  1. 技术图文:02 创建型设计模式(下)

    创建型设计模式(下) 知识结构: 图1 知识结构 单例模式 – 确保对象的唯一性 Sunny 软件公司承接了一个服务器负载均衡软件的开发工作,该软件运行在一台负载均衡服务器上,可以将并发访问和数据流量 ...

  2. 技术图文:02 创建型设计模式(上)

    创建型设计模式(上) 知识结构: 图1 知识结构 简单工厂模式 Sunny 软件公司欲基于 C# 语言开发一套图表库,该图表库可以为应用系统提供各种不同外观的图表,如: 柱状图(histogram) ...

  3. 创建型设计模式对比总结 设计模式(八)

    创建型模式是new 的一种替代方式,可以将对象的创建与具体的类型进行分离 目前已经介绍了5种创建型设计模式(如果简单工厂算一种的话,那就是6种) 分别是: 简单工厂模式.工厂方法模式.抽象工厂模式.建 ...

  4. java面向对象程序设计第三版_JAVA面向对象程序设计之创建型设计模式

    [本文详细介绍了JAVA面向对象程序设计中的创建型设计模式,欢迎读者朋友们阅读.转发和收藏!] 1 基本概念 1.1 什么是设计模式 设计模式( Design pattern )是一套被反复使用.多数 ...

  5. 《Python编程实战:运用设计模式、并发和程序库创建高质量程序》—— 第1章 Python的创建型设计模式...

    本节书摘来自华章出版社<Python编程实战:运用设计模式.并发和程序库创建高质量程序>一 书中的第1章,第1.1节,作者:(美) Mark Summerfield,更多章节内容可以访问云 ...

  6. 从框架源码中学习创建型设计模式

    文章目录 从框架源码中解读创建型设计模式 工厂模式 案例一:RocketMQ源码-创建Producer生产者 案例二:RocketMQ源码-创建过滤器工厂 抽象工厂 案例一:Dubbo源码-创建缓存的 ...

  7. java设计模式之创建型设计模式

    创建型设计模式: 抽象工厂(Abstract Factory): 用途:提供一个接口以创建一系列相关或相互依赖的对象,而无需指定具体的类. 场景: 一个系统要独立于它的产品的创建. 一个系统要由多个产 ...

  8. JavaScript设计模式之创建型设计模式

    此系列总结与<JavaScript设计模式>,总共分为创建型设计模式.结构型设计模式.行为型设计模式.技巧型设计模式和架构性设计模式五大类. github原文地址:YOU-SHOULD-K ...

  9. JavaScript设计模式第一弹-创建型设计模式

    前言 接下来将会为大家介绍设计模式中的创建型设计模式,在此之前需要掌握一定的JavaScript对象继承基础. 简单工厂模式 先说说 什么是简单工厂模式:又叫静态工厂方法,由一个工厂对象决定创建某一种 ...

  10. 设计模式----创建型设计模式(单例模式、工厂方法模式、构建者模式)

    创建型设计模式 单例模式(Singleton Pattern) 单例模式介绍 代码演示 饿汉式(静态常量) 饿汉式(静态代码块) 懒汉式(线程不安全) 懒汉式(线程安全,同步方法) 懒汉式(线程安全, ...

最新文章

  1. uniapp兼容H5和小程序订阅消息授权开发封装,使用方便
  2. 开源APM监控Pinpoint的快速部署和使用
  3. mysql筛选字符个数为8的_听说Mysql你很豪横?-------------分分钟带你玩转SQL高级查询语句(常用查询,正则表达式,运算符)...
  4. 【算法】单源最短路径和任意两点最短路径总结(补增:SPFA)
  5. linux 内核配置 dns,linux bind dns简单配置
  6. php显示时间,php实现用已经过去多长时间的方式显示时间
  7. linux下安装nginx tar包,Linux环境下Nginx的安装
  8. 【Kafka】Kafka 修改某个消费组的偏移量
  9. Scala快速入门到精通 视频教程 百度云网盘下载地址
  10. linux命令获取显示器信息,如何确定液晶显示器是否从Linux命令行打开
  11. qmail加防病毒网关的郁闷经历
  12. 安装SQL Sever2017时出现“Polybase要求安装Oracle JRE 7更新51(64位)或更高版本规则失效”的解决办法
  13. 玩转A2ZS,软改A4
  14. 多多云手机多少钱一月_多多云手机一机分身千变万化 高亢性能体验更加流畅...
  15. libc、glibc和glib的关系
  16. 如何用四条直线把这9个点连起来,要求这四条直线是连续的
  17. 毕业设计之 --- 基于java web的物流信息网的设计与实现
  18. 《费曼学习法》知识体系
  19. 输入法与表情栏无缝切换
  20. AWS、Google、Apple云端宕机背后的故事

热门文章

  1. AR502H-CN开发笔记67:将U盘格式化为FAT32格式
  2. @font-face制作Web Icon
  3. 从TdEngine20行代码引发的风波,看10倍程序员与普通程序员的差距
  4. 问题:已在此计算机上检测到Microsoft Visual C++ 2010 Redistributable的更新版本如何解决
  5. 【专题5: 硬件设计】 之 【68.开关电源 之 buck电路中的电感电流波形】
  6. AD转换中通道的概念
  7. 左程云算法笔记(四)哈希表和有序表的使用、链表
  8. java取余位运算_java学习--高效的除模取余运算(n-1)hash
  9. 微信获取openid方法
  10. 反编译 Progress .r 文件