想象一下,你是一家玩具工厂的老板,主要生产两种玩具:小汽车和积木。最初,你的生产流程很简单,需要什么就直接用 new
创建什么:
// 生产小汽车
Car* myCar = new Car();
// 生产积木
Block* myBlock = new Block();
简单粗暴,效率很高,就像直接从仓库里抓取零件组装一样。但问题也随之而来:
Car
和 Block
类。如果有一天你要生产变形金刚,或者修改 Car
的构造方式,所有用到 new Car()
的地方都要改,简直噩梦!new Car()
,谁知道哪个是玩具汽车,哪个是真正的汽车啊!这时候,你就需要一种更优雅的方式来创建对象,让你的玩具工厂更高效、更灵活,这就是 工厂模式 大显身手的时候了。
简单工厂模式就像你雇了一个专门负责生产玩具的工头,你告诉他要什么玩具,他负责帮你 new
出来。
class Toy {
public:
virtual void play() = 0;
virtual ~Toy() {}
};
class Car : public Toy {
public:
void play() override {
std::cout << "Vroom Vroom!" << std::endl;
}
};
class Block : public Toy {
public:
void play() override {
std::cout << "Stacking blocks..." << std::endl;
}
};
class ToyFactory {
public:
static Toy* createToy(std::string type) {
if (type == "Car") {
return new Car();
} else if (type == "Block") {
return new Block();
} else {
return nullptr; // 或者抛出一个异常
}
}
};
// 使用工厂创建玩具
Toy* myCar = ToyFactory::createToy("Car");
myCar->play(); // 输出: Vroom Vroom!
delete myCar;
现在,你只需要告诉 ToyFactory
你想要什么类型的玩具,它就会帮你创建出来。这样,你就把 new
的操作集中到了 ToyFactory
中,降低了耦合度。
优点:
缺点:
ToyFactory
的 createToy()
方法。这会导致工厂类变得越来越庞大,维护起来也越来越困难。简单工厂虽然解决了直接 new
对象的一些问题,但它仍然不够灵活,无法应对更复杂的需求。想象一下,你的玩具工厂开始生产不同风格的玩具,比如卡通汽车、赛车、工程积木、益智积木等等,简单工厂就显得力不从心了。
为了解决简单工厂的缺点,我们引入 工厂方法模式。就像你为每种类型的玩具都设立一个专门的生产车间,每个车间只负责生产一种类型的玩具。
class ToyFactory {
public:
virtual Toy* createToy() = 0;
virtual ~ToyFactory() {}
};
class CarFactory : public ToyFactory {
public:
Toy* createToy() override {
return new Car();
}
};
class BlockFactory : public ToyFactory {
public:
Toy* createToy() override {
return new Block();
}
};
// 使用工厂方法创建玩具
ToyFactory* carFactory = new CarFactory();
Toy* myCar = carFactory->createToy();
myCar->play(); // 输出: Vroom Vroom!
delete myCar;
delete carFactory;
现在,每种玩具都有自己的工厂,当需要增加一种新的玩具时,只需要创建一个新的工厂类即可,无需修改现有的代码,符合开闭原则。
优点:
缺点:
工厂方法模式解决了简单工厂的缺点,提高了代码的灵活性和可扩展性。但如果你的玩具工厂需要生产一系列相关的玩具,比如汽车系列和积木系列,每个系列又包含不同的款式,工厂方法模式就显得有些力不从心了。这时候,你需要更强大的 抽象工厂模式。
抽象工厂模式就像你把玩具工厂分成不同的生产线,每条生产线负责生产一个系列的玩具。每个系列都包含一系列相关的产品,比如汽车系列包含卡通汽车、赛车、工程车等等。
// 抽象产品:汽车和积木
class Car {
public:
virtual void drive() = 0;
virtual ~Car() {}
};
class Block {
public:
virtual void stack() = 0;
virtual ~Block() {}
};
// 具体产品:卡通汽车、赛车、工程积木、益智积木
class CartoonCar : public Car {
public:
void drive() override {
std::cout << "Cartoon Car driving..." << std::endl;
}
};
class RaceCar : public Car {
public:
void drive() override {
std::cout << "Race Car speeding..." << std::endl;
}
};
class EngineeringBlock : public Block {
public:
void stack() override {
std::cout << "Stacking engineering blocks..." << std::endl;
}
};
class PuzzleBlock : public Block {
public:
void stack() override {
std::cout << "Stacking puzzle blocks..." << std::endl;
}
};
// 抽象工厂:玩具工厂
class ToyFactory {
public:
virtual Car* createCar() = 0;
virtual Block* createBlock() = 0;
virtual ~ToyFactory() {}
};
// 具体工厂:卡通玩具工厂和真实玩具工厂
class CartoonToyFactory : public ToyFactory {
public:
Car* createCar() override {
return new CartoonCar();
}
Block* createBlock() override {
// 这里可以根据需要返回不同的卡通积木
return new PuzzleBlock();
}
};
class RealToyFactory : public ToyFactory {
public:
Car* createCar() override {
return new RaceCar();
}
Block* createBlock() override {
return new EngineeringBlock();
}
};
// 使用抽象工厂创建玩具系列
ToyFactory* cartoonFactory = new CartoonToyFactory();
Car* cartoonCar = cartoonFactory->createCar();
Block* puzzleBlock = cartoonFactory->createBlock();
cartoonCar->drive(); // 输出: Cartoon Car driving...
puzzleBlock->stack(); // 输出: Stacking puzzle blocks...
delete cartoonCar;
delete puzzleBlock;
delete cartoonFactory;
抽象工厂模式定义了一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。这样,你就可以方便地创建不同系列的玩具,而无需修改客户端代码。
优点:
缺点:
选择哪种工厂模式取决于你的具体需求。
就像选择玩具材料一样,没有最好的材料,只有最适合的材料。选择合适的工厂模式,可以让你更好地管理对象的创建过程,提高代码的灵活性、可扩展性和可维护性。
工厂模式和抽象工厂模式都是创建对象的常用设计模式,它们可以帮助你更好地组织和管理代码,提高代码的质量。
记住,设计模式不是万能的,它们只是解决特定问题的工具。在使用设计模式时,要根据实际情况进行选择,不要为了使用而使用。就像玩积木一样,要有创意,才能搭建出你想要的城堡!
希望这篇文章能让你对 C++ 工厂模式和抽象工厂模式有更深入的了解。下次在创建对象时,不妨考虑一下使用这些模式,让你的代码更像玩具,有趣且易于维护!