也许这个标题有点大,但是我是想利用这篇文章来强调一个事实:设计模式不是一层不变的,它需要根据具体问题、具体语言做出具体的实现。设计模式看起来是一种代码模板,但实际并不是。也许有人说,最好的设计模式就是没有模式,这句话其实也算是说到了点子上。所谓设计模式,其实就是能够让我们的代码能够更好的工作——运行起来,或者是让别的开发者更方便使用。
举一个例子:简单工厂模式。这个设计模式并不是 GoF 提出的 23 种设计模式之一,但是在实际编码中经常会遇到。简单来说,简单工厂模式就是使用一个 static 方法,通过一定的标记位的区分,返回不同的产品实例。为了清楚起见,我们先来看一段 Java 的实现:
abstract class Product {
}
class ProductA extends Product {
public ProductA() {
}
}
class ProductB extends Product {
public ProductB() {
}
}
enum ProductType {
A, B
}
class ProductFactory {
public static Product createProduct(ProductType type) {
switch(type) {
case A:
return new ProductA();
case B:
return new ProductB();
default:
return null;
}
}
}
// ...
Product p = ProductFactory.createProduct(ProductType.A); 这段代码很清楚:ProductFactory类的createProduct()方法充当了简单工厂方法,根据实际传入的参数返回具体的产品实例。
我们可以很清楚地看到简单工厂模式的缺陷:工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配的原则。它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类,增加更多的 case 语句。
下面,我们使用 C++ 语言,也要实现这么一个简单工厂模式:
class Product
{
};
class ProductA : public Product
{
};
class ProductB : public Product
{
};
enum ProductType
{
A, B
};
class ProductFactory
{
public:
static Product* createProduct(ProductType type);
};
Product* ProductFactory::createProduct(ProductType type)
{
switch(type)
{
case A:
return new ProductA;
case B:
return new ProductB;
default:
return 0;
}
}
// ...
Product *p = ProductFactory::createProduct(A); 这段代码看上去和前面的 Java 代码没有什么区别。实际上,它就是没有什么区别,就像是把 Java 代码直接翻译成了 C++ 代码。这样的话,Java 代码存在的问题,同样全部到了 C++ 代码中:如果又有了一个ProductC,那就再修改ProductFactory类,再增加一个 case 吧!
有没有更好的方式呢?别忘了,我们使用的是 C++!两种不同的语言,却用了几乎一样的代码,难道不觉得难过么?C++ 比 Java 多了宏,比 Java 多了模板(哦哦,直接无视 Java 的模板吧!我们就事论事,就当没有吧!;-P)。我们不能利用 C++ 特有的语言机制,来让简单工程模式更方便使用吗?于是,我们想到了函数模板:
// ...
class ProductFactory
{
public:
template<class T>
static Product * createProduct()
{
return new T;
}
}
// ...
Product *p = ProductFactory::createProduct<ProductA>(); 这下如何?增加新的类,也无需改变任何已有代码。因为我们利用 C++ 的函数模板特性,编写了一个函数模板,每次只需将我们需要生成的类传入,就可以直接获得该类实例的指针。虽然我们按照简单工厂模式编写了代码,却解决了简单工厂模式的一些缺陷。
上面的例子很简单,却能够清楚反应我所要表达的内容。在应用设计模式,以及其它代码的时候,请注意语言特有的特性。我们编写代码,并不是要使用所有语言的最大公约数,而是要充分利用语言特性,方便我们的代码编写。