第 3 章 工厂方法及抽象工厂模式代码
#include<iostream>
#include<memory>
struct Point2D {
int x;
int y;
};
enum class Material {
brick,
aerated_concrete,
drywall,
};
enum class WallType {
basic,
main,
partition,
};
class Wall {
Point2D start;
Point2D end;
int elevation;
int height;
public:
Wall(Point2D start, Point2D end, int elevation, int height)
:start(start),end{end},elevation{elevation},height{height} {
}
bool intersects(const Wall& wall) {
return false;
}
virtual void print(std::ostream &os) const {
os << "start: " << start.x << ", " << start.y
<< "\nend: " << end.x << ", " << end.y
<< "\nelevation: " << elevation
<< "\nheight: " << height;
}
friend std::ostream& operator<<(std::ostream& os, const Wall& wall) {
wall.print(os);
return os;
}
};
#if 0
class SoildWall: public Wall {
int width;
Material material;
public:
SoildWall(Point2D start, Point2D end, int elevation, int height,
int width, Material material)
:Wall{start,end,elevation,height}, width{width}, material{material} {
if (elevation < 0 && material == Material::aerated_concrete) {
throw std::invalid_argument("elevation");
}
if (width < 120 && material == Material::brick) {
throw std::invalid_argument("width");
}
}
};
void testNoFactory() {
try
{
Point2D start{0,0}, end{0,300};
SoildWall tmp(start, end, -1, 100, 100, Material::brick);
}
catch (const std::exception &e)
{
std::cerr <<"create wall error argument: "<< e.what() << '\n';
}
}
#else
class SoildWall: public Wall {
friend class WallFactory;
int width;
Material material;
protected:
SoildWall(Point2D start, Point2D end, int elevation, int height,
int width, Material material)
: Wall{start, end, elevation, height}, width{width}, material{material}{
}
public:
void print(std::ostream &os) const override {
Wall::print(os);
os << "\nwidth: " << width
<< "\nmaterial: " << static_cast<int>(material);
}
friend std::ostream& operator<<(std::ostream& os, const SoildWall& wall) {
wall.print(os);
return os;
}
static SoildWall create_main(Point2D start, Point2D end, int elevation, int height) {
return SoildWall(start, end, elevation, height, 375, Material::aerated_concrete);
}
static std::unique_ptr<SoildWall> create_partition(Point2D start,
Point2D end, int elevation, int height) {
return std::make_unique<SoildWall>(SoildWall(start, end, elevation, height, 120, Material::brick));
}
static std::shared_ptr<SoildWall> create_main2(Point2D start,
Point2D end, int elevation, int height) {
if (elevation < 0) {
return {};
}
return std::make_shared<SoildWall>(SoildWall(start,
end, elevation, height, 120, Material::brick));
}
};
void testFactoryMethod() {
Point2D start{0, 0}, end{0, 3000};
const auto main_wall = SoildWall::create_main({0, 0}, {0, 3000}, 2700, 3000);
std::cout << main_wall << "\n";
}
void testFactoryCreateMain2() {
const auto also_main_wall = SoildWall::create_main2({0,0},{0,3000}, -2000, 3000);
if (!also_main_wall) {
std::cout << "main wall create failed." << std::endl;
}
}
#endif
#include<vector>
class WallFactory {
private:
static std::vector<std::weak_ptr<Wall>> walls;
public:
static std::shared_ptr<SoildWall> create_mian(Point2D start,
Point2D end, int elevation, int height) {
const auto this_wall = new SoildWall(start, end, elevation,
height, 120, Material::brick);
for (const auto wall : walls) {
if (auto p = wall.lock()) {
if (this_wall->intersects(*p)) {
delete this_wall;
return {};
}
}
}
std::shared_ptr<SoildWall> ptr(this_wall);
walls.push_back(ptr);
return ptr;
}
static std::shared_ptr<Wall> create_wall(WallType type, Point2D start,
Point2D end, int elevation, int height) {
switch(type) {
case WallType::main:
{
return std::make_shared<SoildWall>(SoildWall(start, end, elevation, height,
375, Material::aerated_concrete));
}
case WallType::partition:
{
return std::make_shared<SoildWall>(SoildWall(start, end, elevation, height,
120, Material::brick));
}
case WallType::basic:
{
return std::shared_ptr<Wall>{new Wall(start, end, elevation, height)};
}
default:
return {};
}
}
};
std::vector<std::weak_ptr<Wall>> WallFactory::walls;
void testWallFactory() {
const auto partition = WallFactory::create_mian({2000,0}, {2000,4000}, 0, 2700);
std::cout << *partition << std::endl;
}
void testPolymorphicFactory()
{
auto also_partition =
WallFactory::create_wall(WallType::partition, {0,0}, {5000, 0}, 0, 4200);
if (also_partition) {
auto tmp = std::dynamic_pointer_cast<SoildWall>(also_partition);
if (tmp == nullptr) {
std::cout << "hahhahahha" << std::endl;
}
std::cout << "\ntestPolymorphicFactory: \n" <<
*std::dynamic_pointer_cast<SoildWall>(also_partition) << "\n";
}
std::cout << "\ntestPolymorphicFactory2: \n" <<
(*also_partition) << "\n";
}
namespace NestFactory{
class Wall
{
Point2D start;
Point2D end;
int elevation;
int height;
public:
Wall(Point2D start, Point2D end, int elevation, int height)
: start(start), end{end}, elevation{elevation}, height{height}
{
}
bool intersects(const Wall &wall)
{
return false;
}
virtual void print(std::ostream &os) const
{
os << "start: " << start.x << ", " << start.y
<< "\nend: " << end.x << ", " << end.y
<< "\nelevation: " << elevation
<< "\nheight: " << height;
}
friend std::ostream &operator<<(std::ostream &os, const Wall &wall)
{
wall.print(os);
return os;
}
private:
class BasicWallFactory{
BasicWallFactory()=default;
public:
std::shared_ptr<Wall> create(const Point2D start,
const Point2D end,
const int elevation, const int height) {
Wall *wall = new Wall(start, end, elevation, height);
return std::shared_ptr<Wall>(wall);
}
};
public:
static BasicWallFactory factory;
};
Wall::BasicWallFactory Wall::factory{};
void testNestFactory() {
auto basic = Wall::factory.create({0, 0}, {5000, 6666}, 0, 4444);
std::cout << "\n3.5 ======= \n" << *basic << "\n";
}
};
#include<map>
namespace AbstractFactory{
struct HotDrink {
virtual void prepare(int volume) = 0;
};
struct Tea: HotDrink {
void prepare(int volume) override {
std::cout << "take tea bag, boil water, pour " << volume
<< "ml, add some lemon" << std::endl;
}
};
struct Coffee: HotDrink {
void prepare(int volume) override {
std::cout << "take coffee bag, boil water, pour " << volume
<< "ml, add some lemon" << std::endl;
}
};
std::unique_ptr<HotDrink> make_drink(std::string type) {
std::unique_ptr<HotDrink> drink = nullptr;
if (type == "tea") {
drink = std::make_unique<Tea>();
drink->prepare(200);
} else {
drink = std::make_unique<Coffee>();
drink->prepare(50);
}
return drink;
}
class HotDrinkFactory {
public:
virtual std::unique_ptr<HotDrink> make() const = 0;
};
class CoffeeFactory: public HotDrinkFactory {
public:
std::unique_ptr<HotDrink> make() const override {
return std::make_unique<Coffee>();
}
};
class TeaFactory: public HotDrinkFactory {
public:
std::unique_ptr<HotDrink> make() const override {
return std::make_unique<Tea>();
}
};
class DrinkFactory {
std::map<std::string, std::unique_ptr<HotDrinkFactory>> hot_factory;
public:
DrinkFactory() {
hot_factory["coffee"] = std::make_unique<CoffeeFactory>();
hot_factory["tea"] = std::make_unique<TeaFactory>();
}
std::unique_ptr<HotDrink> make_drink(const std::string &name) {
auto drink = hot_factory[name]->make();
drink->prepare(200);
return drink;
}
};
};
#include<functional>
namespace FunctionFactory{
class DrinkWithVolumFactory
{
std::map<std::string, std::function<std::unique_ptr<AbstractFactory::HotDrink>()>> factories;
public:
DrinkWithVolumFactory() {
factories["tea"] = [] {
auto tea = std::make_unique<AbstractFactory::Tea>();
tea->prepare(200);
return tea;
};
factories["coffee"] = [] {
auto coffee = std::make_unique<AbstractFactory::Coffee>();
coffee->prepare(50);
return coffee;
};
}
inline std::unique_ptr<AbstractFactory::HotDrink>make_drink(const std::string &name);
};
std::unique_ptr<AbstractFactory::HotDrink>
DrinkWithVolumFactory::make_drink(const std::string &name)
{
return factories[name]();
}
void testFunctionFunctionFactory() {
std::cout << "\n" << __FUNCTION__ << " start. \n";
DrinkWithVolumFactory dwvf;
dwvf.make_drink("tea");
dwvf.make_drink("coffee");
std::cout << __FUNCTION__ << " end. \n\n";
}
}
int main()
{
testFactoryMethod();
testFactoryCreateMain2();
testWallFactory();
testPolymorphicFactory();
NestFactory::testNestFactory();
FunctionFactory::testFunctionFunctionFactory();
return 0;
}