设计模式(三)
某些情况,可能会过度地使用继承来扩展对象的功能;
由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;
随着子类增多, 各种子类的组合会导致更多子类的膨胀
需要使用对象功能的扩展,能够根据需要来动态地实现,避免扩展功能的增多带来的子类膨胀
装饰者模式
装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种模式通过创建一个包装对象(装饰者)来包裹真实的对象,并提供增强的功能
eg:咖啡
如果我们想要为咖啡添加不同的调料(如糖、牛奶、巧克力等),我们可能需要为每种可能的组合创建一个类
c++
class Coffee {
public:
virtual std::string getDescription() const = 0;
virtual double cost() const = 0;
};
class SimpleCoffee : public Coffee {
public:
std::string getDescription() const override {
return "Simple Coffee";
}
double cost() const override {
return 10.0;
}
};
class CoffeeWithMilk : public Coffee {
public:
std::string getDescription() const override {
return "Simple Coffee with Milk";
}
double cost() const override {
return 12.0; // Coffee cost + Milk cost
}
};
class CoffeeWithSugar : public Coffee {
public:
std::string getDescription() const override {
return "Simple Coffee with Sugar";
}
double cost() const override {
return 11.0; // Coffee cost + Sugar cost
}
};
// ... 更多组合类 ...
这种无脑的使用继承,会造成子类过于繁多,臃肿;
解决方法是:
通过组合来增加灵活性,继承是编译时静态决定的;而组合则是运行时,动态地添加或更换组件
继承会导致子类和父类紧密的耦合,父类若变,子类有可能都受影响
组合可以重用 不同类的对象和功能
使用装饰者模式:
创建一个装饰者基类,然后为每种调料创建一个装饰者类
c++
class Coffee {
public:
virtual std::string getDescription() const = 0;
virtual double cost() const = 0;
virtual ~Coffee() {}
};
class SimpleCoffee : public Coffee {
public:
std::string getDescription() const override {
return "Simple Coffee";
}
double cost() const override {
return 10.0;
}
};
// Decorator
class CoffeeDecorator : public Coffee {
protected:
Coffee* coffee;
public:
CoffeeDecorator(Coffee* coffee) : coffee(coffee) {}
std::string getDescription() const override {
return coffee->getDescription();
}
double cost() const override {
return coffee->cost();
}
};
// Concrete Decorators
class Milk : public CoffeeDecorator {
public:
Milk(Coffee* coffee) : CoffeeDecorator(coffee) {}
std::string getDescription() const override {
return CoffeeDecorator::getDescription() + ", Milk";
}
double cost() const override {
return CoffeeDecorator::cost() + 2.0; // Milk cost
}
};
class Sugar : public CoffeeDecorator {
public:
Sugar(Coffee* coffee) : CoffeeDecorator(coffee) {}
std::string getDescription() const override {
return CoffeeDecorator::getDescription() + ", Sugar";
}
double cost() const override {
return CoffeeDecorator::cost() + 1.0; // Sugar cost
}
};
// ... 更多装饰者类 ...
这样就可以动态的添加调料到咖啡中
c++
int main() {
Coffee* myCoffee = new SimpleCoffee();
std::cout << myCoffee->getDescription() << " - $" << myCoffee->cost() << std::endl;
myCoffee = new Milk(myCoffee);
std::cout << myCoffee->getDescription() << " - $" << myCoffee->cost() << std::endl;
myCoffee = new Sugar(myCoffee);
std::cout << myCoffee->getDescription() << " - $" << myCoffee->cost() << std::endl;
// Clean up
delete myCoffee;
return 0;
}
/*输出:
Simple Coffee - $10
Simple Coffee, Milk - $12
Simple Coffee, Milk, Sugar - $13
*/
可以看到,在装饰者类中
既继承了父类,又定义了父类;即:is-a has-a
同时继承父类,组合子类
通常这种继承父类,又再类中定义了父类,八成是装饰者模式