模式一:单例模式
(一) 介绍
定义:确保某一个类只有一个实例,并且自行实例化并向整个系统提供这个实例。
(二) 实践
优点:
- 减少内存开销,特别是一个对象需要频繁的创建和销毁时
- 减少系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久贮存在内存中,这里要注意垃圾回收机制,特别是J2EE.
- 避免对资源的多重利用
- 可以设置全局的访问点,优化和共享资源
缺点:
- 没有接口,扩展很难
- 对测试不利
- 与单一职责有冲突
应用场景:
- 要求生成唯一序列号的环境
- 在整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,使用线程安全的单例模式保持计数器的值
- 创建一个对象需要消耗过多的资源,比如访问I/O和数据库
- 需要定义大量的静态常量和静态方法
- Spring中,每个Bean默认的都是单例的
//同步且高效率的单例模式:
class Single{
private static Single s= null;
private Single(){}
public static Single getInstance(){
if(s==null){
synchronized(Single.class){
if(s==null)
s=new Single();
}
}
}
}
单例模式的扩展-有上线的多例模式
//旗舰店总共有宝马,奔驰两种车,有五个人从该旗舰店买车
public class Car{
private static int maxNumOfCar = 2;
private static ArrayList<String> nameList= new ArrayList<String>();
private static ArrayList<Car> carList= new ArrayList<Car>();
private static int countNumOfCar=0;
static{
for(int i=0;i<maxNumOfCar ;i++){
carList.add(new Car("车"+(i+1)));
}
}
private Car(){}
private Car(String name){
nameList.add(name);
}
//旗舰店开始展出车
public static Car getInstance(){
Random random= new Random();
countNumOfCar= random.nextInt(maxNumOfCar);
return carList.get(countNumOfCar);
}
public static void drive(){
System.out.println("开车兜风");
}
}
//开始购买车
public class people{
public static void main(String[] args){
int peopleNum= 10;
for(int i=0;i<peopleNum;i++){
//构建一个单例模式
Car car= Car.getInstance();
car.drive();
}
}
}
模式二:工厂方法模式
(一) 介绍
定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
工厂模式通用图:
- 抽象产品类Product负责定义产品的共性,实现对事物最抽象的定义
- Creator为抽象类创建类,也就是抽象工厂
- 如何创建产品类是由具体实现的工厂ConcreteCreator完成的
下面给出工厂类通用模板接口设计:
//抽象产品类
public abstract class Product{
//产品类的公共方法
public void method1(){
//业务逻辑处理
}
//抽象方法
public abstract void method2();
}
//具体的产品可以有多个,都继承于抽象产品类
public class ConcreteProduct1 extends Product{
public void method2(){
//业务逻辑处理
}
}
public class ConcreteProduct2 extends Product{
public void method2(){
//业务逻辑处理
}
}
抽象工厂类负责实现产品对象的产生
//抽象工厂类
public abstract class Creator{
/*
* 创建一个产品对象,其输入参数类型可以自行设置
*通常为String,Enum,Class等,当然也可以为空
*/
public abstract <T extends Product> T createProduct(Class<T> c);
}
具体如何产生一个产品的对象,是由具体的工厂类实现的
//具体工厂类
public class ConcreteCreator extends Creator{
public <T extends Product> T createProduct(Class<T> c){
Product product = null;
try{
product=(Product)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
//异常处理
}
return (T) product
}
}
实际场景应用
public class Client{
public static void main(String[] args){
Creator creator = new ConcreteCreator();
Product product = creator.creatorProduct(ConcreteProduct1.class);
//继续业务处理
}
}
(二) 应用
优点:
- 良好的封装性,代码结构清晰,一个调用者需要一个具体的产品对象,只要知道这个产品的类名就可以了
- 工厂方法模式的扩展性好
- 屏蔽产品类。产品类的实例化是由工厂类负责的,一个产品对象具体由哪一个产品生成是由工厂类决定
- 解耦框架
使用场景
- 工厂类模式是new一个对象的替代品,需要慎重的考虑是否需要一个工厂类进行管理,增加了代码的复杂性
- 需要灵活的、可扩展性的框架时,可以考虑采用工厂模式。比如网路测试中,需要测试不同的协议的流量,可以看成不同的产品,设计一个工厂类,根据传入的条件参数产生不同的产品(协议)
- 可用于异构项目中
- 可以使用在测试驱动开发的框架下
(三) 扩展
1、缩小为简单工厂模式
//定义人类
public interface Human{
public void getColor();
public void talk();
}
//创建三个不同的人种
public class BlackHuman implements Human{
public void getColor() {
//业务逻辑
}
public void talk(){
//业务逻辑
}
}
public class YellowHuman implements Human{
public void getColor() {
//业务逻辑
}
public void talk(){
//业务逻辑
}
}
public class WhiteHuman implements Human{
public void getColor() {
//业务逻辑
}
public void talk(){
//业务逻辑
}
}
而工厂实现生产人类方法的输入参数应该是Human接口的实现类,所以应该为Class类型,采用泛型为createHuman的输入参数进行限制:必须是Class类型;必须是Huamn的实现类。
public abstract class AbstractHumanFactory{
public abstract <T extends Human> T createHuman(Class<T> c);
}
然后就是HumanFactory的创建以及实例化
public class HumanFactory extends AbstractHumanFactory {
public <T extends Human> T createHuman(Class<T> c){
Human human= null;
try{
//产生一个人种
human=(T)Class.forName(c.getName()).newInstance();
}catch (Exception e){
//异常描述
}
return (T)human;
}
}
最后就是Client的创建,进行生产人类
public class Client{
public static void main(String[] args){
AbstractHumanFactory factory = new HumanFactory();
Human whiteHuman= factory.createHuman(WhiteHuman.class);
whiteHuman.getColor();
whiteHuman.talk();
//创建实例化其它的两种人类
...
}
}
简化为下面的含有static参数的形式,在类图中去掉了AbstractHumanFactory 抽象类,同时把createHuman方法设置为静态类,简化了类的创建过程。
程序代码如下:
public class HumanFactory{
public static <T extends Human> T createHuman(Class<T> c){
//定义一个生产出的人种
Human human= null;
try{
//产生一个人种
human=(T)Class.forName(c.getName()).newInstance();
}catch (Exception e){
//异常描述
}
return (T)human;
}
}
//相应的Client也会发生改动
public class Client{
public static void main(String[] args){
Human whiteHuman= HumanFactory.createHuman(WhiteHuman.class);
whiteHuman.getColor();
whiteHuman.talk();
//创建实例化其它的两种人类
...
}
}
2、升级为多个工厂类
3、替代单例模式
4、延迟初始化
一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用
ProductFactory负责产品类对象的创建工作,并且通过一个prMap变量产生一个缓存。
//延迟加载的工厂类
public class ProductFactory{
private static final Map<String,Product> proMap = new HashMap();
public static synchronized Product createProduct(String type) throws Exception {
Product product = null;
//如果Map中已经有这个对象
if(proMap.containsKey(type)){
product= proMap.get(type);
}else{
if(type.equals("Product1")){
product= new ConcreteProduct1();
}else{
product= new ConcreteProduct2();
}
//同时把对象放到缓存容器中
proMap.put(type,product);
}
return product;
}
}
模式三:抽象工厂模式
(一)介绍:
定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类
通用类图:
通用源码图:
代码模板:
public abstract class AbstractProductA{
//每个产品共有的方法
public void shareMethod(){
}
//每个产品相同的方法,不同的实现
public abstract void doSomething();
}
具体产品实现类:
//产品A1的实现类
public class ProductA1 extends AbstractProductA{
public void doSomething(){
System.out.println("产品A1的实现方法");
}
}
//产品A2的实现类
public class ProductA2 extends AbstractProductA{
public void doSomething(){
System.out.println("产品A2的实现方法");
}
}
//产品B1的实现类
public class ProductB1 extends AbstractProductB{
public void doSomething(){
System.out.println("产品B1的实现方法");
}
}
//产品B2的实现类
public class ProductB2 extends AbstractProductB{
public void doSomething(){
System.out.println("产品B2的实现方法");
}
}
抽象工厂AbstractCreator的职责是定义每个工厂要实现的功能,在通用代码中,抽象工厂类实现了两个产品族的产品创建(如果有N个产品族,在抽象工厂类中就有N个创建方法)
public abstract class AbstractCreator {
//创建A产品家族
public abstract AbstractProductA createProductA();
//创建B产品家族
public abstract AbstractProductB createProductB();
}
如何创建一个产品,就应该由具体的实现类来完成(有M个产品等级就应该有M个实现工厂类,在每个实现工厂中,实现不同产品族的生产任务)
//产品等级1的实现类
public class Creator1 extends AbstractCreator {
//只生产产品等级为1的A类产品
public AbstractProductA creatProductA(){
return new ProductA1();
}
//只生产产品等级为1的B类产品
public AbstractProductB creatProductB(){
return new ProductB1();
}
}
//产品等级2的实现类
public class Creator2 extends AbstractCreator {
//只生产产品等级为1的A类产品
public AbstractProductA creatProductA(){
return new ProductA2();
}
//只生产产品等级为1的B类产品
public AbstractProductB creatProductB(){
return new ProductB2();
}
}
最后,在具体的业务中产生一个无关的对象
public class Client {
public static void main(Stirng[] args) {
//定义两个工厂
AbstractCreator creator1 = new Creator1();
AbstractCreator creator2 = new Creator2();
//产生分别具有两个等级的两个不同类型的对象
AbstractProductA a1= creator1.createProductA();
AbstractProductA a2= creator2.createProductA();
AbstractProductB b1= creator1.createProductB();
AbstractProductB b2= creator2.createProductB();
//实现业务逻辑
..........
}
}
(二)应用:
优点:
- 封装性
- 产品族的约束为非公开状态
缺点:
产品族扩展非常困难
使用场景:
一个对象族都有相同的约束关系
注意事项:
抽象工厂模式产品族(产品个数)扩展困难,而产品等级(产品属性)扩展容易,即横向扩展容易,纵向扩展难。
(未完待续…)
参考文献
《设计模式之禅》 秦小波著
《Java核心技术 卷I》 周立新等译
《算法分析与设计》 霍红卫译