设计模式非常重要,是理解设计架构的基本功,也是编写出优雅健壮代码不可或缺的技能。
接下来会介绍23中Java中的设计模式,每一种模式必须要知道:
1,是什么样的结构;
2,在什么情况下用,有什么样的优缺点;
3,有哪些注意事项;
第一种:工厂模式
—为创建对象提供接口
1. 结构
工厂模式分为:
* 简单工厂(Simple Factory)模式;
* 工厂方法(Factory Method)模式;
* 抽象工厂(Abstrct Factory)模式;//在23种模式中,抽象工厂是单独的一种,这里归纳在一起;
简单工厂模式的结构:
- 抽象产品:定义客户所需要的功能接口;
- 具体产品:具体实现接口的具体实现类,一般有多个实现类;
- 工厂类:选择合适的产品来创建接口对象
- 通常可以把简单工厂类实现成一个工具类;
- 还可以将简单工厂的构造方法私有化,从而防止客户端无谓地创造简单工厂实例;
- 虽然工厂是”万能”的,即可以创造各种类型的对象实例(接口,抽象类和普通类);但是通常创建对象的范围需要控制在一个独立的组件级别或者一个模块级别;
- 客户端:通过工厂类去获取接口的对象,然后面向接口对象编程
//抽象产品类:通常是接口
public interface Tank{
public void shoot();
}
//具体产品类,实现接口,对客户端透明!
public class HeroTank implements Tank{
public void shoot(){
//...具体实现
}
}
public class EnermyTank implements Tank{
public void shoot(){
//...具体实现
}
}
//关键的工厂类:
public class TankFactory{
public static Tank createHeroTank(){
return new HeroTank();
}
public static Tank createEnermyTank(){
return new EnermyTank();
}
}
//客户端
public class Game{
public void beginGame(){
Tank tank1 = TankFactory.createHeroTank();
Tank tank2 = TankFactory.createEnermyTank();
//面向接口编程,扩展性刚刚的。。。。
tank1.shoot();
tank2.shoot();
}
}
其实仅仅是将创建对象的过程,“封装”到了工厂类中,从而完成了客户端和具体实现类的封装隔离;对于客户端来说,只需要知道有Tank这个Api接口和TankFactory这个获取接口对象的工厂类就行了,完全不用care具体的Tank接口子类是如何实现的。这样一来,具体实现发生了变化,完全不用变动客户端;这个变化会被工厂类吸收并且屏蔽掉。
2. 在什么情况下用:
简单工厂模式的设计源于接口,因此首先需要复习一下Java的借口:
- 接口是实现类对外的外观,可以实现不同类的相同行为,而不用考虑这些类之间的层次关系;
- 接口的思想是”封装隔离“:对被隔离体行为的封装;对外部调用和内部实现进行隔离;
- 接口时系统可插拔性的保证;
- 什么时候使用接口,什么时候使用抽象类?
- 优先使用接口;
- 既要定义子类的行为,又要为子类提供共有的实现了的方法;
- 只要是创建对象时,都可以考虑是否可以使用工厂模式;可以将创建对象的职责集中管理控制;
- 特别是对象的初始化工作比较长时:代码长需要分割再封装(减少封装体之间的耦合性)起来,不仅可以将风险分散,以后修改或者扩展的时候,只要修改某一段,不会出现牵一发动全身的后果;
- 编码时无法预测需要创建哪一种类的实例
- 相似类比较多,需要根据具体情况进行创建;
- 创建接口或者抽象类的对象;
- 想要完全封装隔离具体实现,让外部只能通过接口来操作封装的实现;
3. 注意事项
其实,简单工厂的难点在于在客户端中“如何选择”实现;通常可以通过1. 客户端传入的静态参数;2. 由工厂读取某个内存值,或者数据库中的值,动态传入参数;3. 配置文件,通过反射来实现;
4. 工厂方法模式
简单方法模式最大的缺点是不完全满足OCP原则(Open for
Extension,Close for Modification);通过将创建产品对象的工厂定义为一个接口,由子类负责具体的创建产品工作,从而实现在不修改工厂类的情况下可以达到修改扩展新工厂的功能。
但是,通常不使用这种模式,虽然先进,但是不一定方便实用。。。呵呵