也许这个标题有点大,但是我是想利用这篇文章来强调一个事实:设计模式不是一层不变的,它需要根据具体问题、具体语言做出具体的实现。设计模式看起来是一种代码模板,但实际并不是。也许有人说,最好的设计模式就是没有模式,这句话其实也算是说到了点子上。所谓设计模式,其实就是能够让我们的代码能够更好的工作——运行起来,或者是让别的开发者更方便使用。
举一个例子:简单工厂模式。这个设计模式并不是 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++ 的函数模板特性,编写了一个函数模板,每次只需将我们需要生成的类传入,就可以直接获得该类实例的指针。虽然我们按照简单工厂模式编写了代码,却解决了简单工厂模式的一些缺陷。
上面的例子很简单,却能够清楚反应我所要表达的内容。在应用设计模式,以及其它代码的时候,请注意语言特有的特性。我们编写代码,并不是要使用所有语言的最大公约数,而是要充分利用语言特性,方便我们的代码编写。