@Author:云都小生
设计模式简述
甄子丹与王宝强一起演的电影《一个人的武林》中,有这么一段话让我印象深刻——“先拳后腿次擒拿,兵器内外武合一”。由外到内修炼,内外结合方可小成。在软件开发领域,编程语言就相当于拳腿,各种开发工具就像是兵器,而这些东西都属于外功。那什么是内功呢?从数据结构到算法,从重构到设计模式等,这些都算是程序员的内功。拥有雄厚的内功,是所有武林人士的追求。
从今天开始今天,我也要来修修内功啦,赶紧上车吧~
几个问题引发的血案
在面向对象的程序设计中,平时我们在设计一个类的时候,经常会把大量的属性、方法封装在一起。但是在面向对象设计中有一个原则—— 单一职责原则,如果你把所有的功能都放在同一个类里面,那这个类就太“累”了,承当太多,这样一来代码的可维护性就会很低。
所以我们通常会把不同功能的,分成不同的类封装起来。在创建类的过程中,我们经常都会使用继承,来提高程序的可复用性,但是继承造成了高耦合,只要父类改了,子类就会跟着改。继承早就了高耦合。
在创建一个对象的时候,我们通常的方式都是用new的方式,除了效率不高外,还有另外一个问题。new XXX 如果我们定义的子类太多,在创建父类引用指向子类对象的时,经常会忘记子类的名字,得一个个去查,那岂不是很麻烦。
并且,如果一个类中没有对属性进行初始化,那我们就需要在对象创建的时候,给属性进行初始化,这样客户端的代码就会变得特别冗长。
综上问题,我们都可以用工厂模式来进行优化。工厂模式分为三类,分别是简单工厂模式、工厂方法模式、抽象工厂模式,对,难度一个比一个高。这一节我们来说一下简单工厂模式。
简单工厂模式
简单工厂模式有两个特点:
1. 将对象创建封装起来
2. 将具体化对象的代码放到子类中去
简单的说,用了简单工厂方法,我想创建一个对象,直接把信息传进去,对象就创建好了。具体的工作,都是由其他类(类创建者)去做,客户端不管。
先给一张图:
具体的做法是这样:
1. 将公共的属性和方法封装成一个抽象类或接口;
2. 通过继承(或实现),产生各个子类(或实现接口的类),需要考虑单一职责原则,不能设计一个包罗万象的类;
3. 创建一个工厂类,这个工厂类用于生产不同的对象,可以根据传入的不同参与,生产出相对应的对象;
我们来看一下代码,边看边分析。
代码分析
//抽象产品类,封装产品的共同属性和方法
public abstract class Product { //抽象产品
public void publicMethod() {
System.out.println("产品公共方法。");
}
abstract void productTest();
}
//产品One
public class oneProduct extends Product {
void productTest() {
System.out.println("One product test:OK!");
}
}
//产品Two
public class twoProduct extends Product {
void productTest() {
System.out.println("Two product test:OK!");
}
}
//工厂类
public class Factory {
public static Product getProduct(String arg) {
Product product = null;
if (arg.equalsIgnoreCase("One")) {
product = new oneProduct();
//初始化设置One PSroduct
}
else if (arg.equalsIgnoreCase("Two")) {
product = new twoProduct();
//初始化设置Two PSroduct
}
return product;
}
}
//客户端类
public class Test {
public static void main(String[] args) {
Product product;
product = Factory.getProduct("one"); //通过工厂类创建产品对象
product.productTest();
}
}
这样一来,我们就实现了客户端与对象对象创建的分离。有时候我们还可以将工厂与产品类合并,将对象创建的静态方法迁移到具体的产品类中。
适用范围与优缺点
简单工厂方法适用于:
1. 工厂类负责创建的对象比较少的时候;
2. 客户端只需要传入参数,并不关心对象的创建。
综上所述,我们引入一些简单工厂方法的优点:
1. 创建对象更加灵活了,实现了对象创建与客户端类的分离;
2. 在创建对象的过程中,我们只需要传入参数,不需要具体的去创建每一个对象。
缺点:
1. 难以扩展,一旦添加新的产品,就不得不修改工厂类,违背了“开闭原则;
2. 一旦工厂类不能工作,整个系统都将受到影响。
参考资料
史上最全设计模式导学目录
书籍:@K_Eckel《23种设计模式(C++)》