现代c++改变了很多设计模式的实现方式,为了保持与时俱进,阅读了”Design Pattern in Modern C++“这本书,会记录下来在阅读中的一些心得体会,Part1主要包括 工厂模式,建造者模式与单例模式的现代实现


Factory

Abstract Factory

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
struct HotDrinkFactory {
  virtual unique_ptr<HotDrink> make() const = 0;  };
};
struct CoffeeFactory : HotDrinkFactory{
 unique_ptr<HotDrink> make() const override {
 return make_unique<Coffee>();
}};

class DrinkFactory {
  map<string, unique_str<HotDrinkFactory>> hot_factories;
public:
  DrinkFactory(){
   hot_factories["coffee"] = make_unique<CoffeeFactory>();
   hot_factories["tea"] = make_unique<TeaFactory>();
  }
  unique_ptr<HotDrink> make_drink(const string& name) {
   auto drink = hot_factories[name]->make();
   drink->prepare(200); // oops!
   return drink;
  }
};

这种写法避免了简单工厂模式冗长的switch case,会初始化所有的工厂,通过map来调用特殊类的工厂。

Functional Factory

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class DrinkWithVolumeFactory
{
 map<string, function<unique_ptr<HotDrink>()>> factories;
public:
DrinkWithVolumeFactory() {
  factories["tea"] = [] {
  	auto tea = make_unique<Tea>(); tea->prepare(200);
  	return tea;
  };
}
inline unique_ptr<HotDrink> DrinkWithVolumeFactory::make_drink(const string& name) {
	return factories[name](); 
 }
};

这种工厂使用了lambda+function,存储了每个name对应的构建方法。不用再继承很多的派生工厂,看起来非常优雅。

==tips:==

boost::archive::text_oarchive 可以通过stringstream的方式序列化一个类,很方便


Singleton

Old style(double check lock)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Database {
	// same members as before, but then...
	static Database& instance(); 
private:
	static boost::atomic<Database*> instance; 
	static boost::mutex mtx;
};
Database& Database::instance() {
	Database* db = instance.load(boost::memory_order_consume);
	if (!db) {
		boost::mutex::scoped_lock lock(mtx);
    db = instance.load(boost::memory_order_consume);
		if (!db) {
			db = new Database();
      instance.store(db, boost::memory_order_release);
 		}
  }
}

C++11

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Database{
protected:
  Database();
public:
  static Database& get() {
    static Database database;
    return database;
  }
  //如果不从静态区分配内存,而是从堆上分配
  static Database& get() {
    static Database* database = new Database();
    return *database;
  }
  Database(Database const&) = delete;
  Database(Database&&) = delete;
  Database& operator=(Database const&) = delete;
  Database& operator=(Database &&) = delete;
}

Builder

这个模式实际使用起来比较常见,有个使用方式比较有趣,这里列出来

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class PersonAddressBuilder : public PersonBuilderBase {
	typedef PersonAddressBuilder self; 
public:
	explicit PersonAddressBuilder(Person& person) : PersonBuilderBase{ person } {}
	self& at(std::string street_address){
  	person.street_address = street_address;
	 	return *this;
	}

  self& with_postcode(std::string post_code) { ... }
  self& in(std::string city) { ... }
};

//使用,赋值属性后返回引用可以持续进行属性赋值
Person p = Person::create()
  .lives().at("123 London Road")
          .with_postcode("SW1 1GB")
          .in("London")
  .works().at("PragmaSoft")
          .as_a("Consultant")
          .earning(10e6);