Java设计模式(三):创建型模式(单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式)

一·单例设计模式

1.1 单例设计模式介绍

所 谓 类 的 单 例 设 计 模 式 , 就 是采 取 一 定 的 方 法 保 证 在 整 个 的 软 件 系 统 中 , 对 某 个 类 只 能 存 在 一 个 对 象 实 例 , 并且该类只提供一个取得其对象实例的方法(静态方法)。 

	比如 Hibernate 的 SessionFactory,它充当数据存储源的代理,并负责创建 Session 对象。SessionFactory 并不是 轻量级的,一般情况下,一个项目通常只需要一个 SessionFactory 就够,这是就会使用到单例模式。 

1.2 单例设计模式八种方式

单例模式有八种方式:
 
	1) 饿汉式(静态常量) 
	2) 饿汉式(静态代码块)
	3) 懒汉式(线程不安全) 
	4) 懒汉式(线程安全,同步方法) 
	5) 懒汉式(线程安全,同步代码块) 
	6) 双重检查 
	7) 静态内部类 
	8) 枚举

1.3 饿汉式(静态常量 )

饿汉式(静态常量)应用实例 
步骤如下: 
	1) 构造器私有化 (防止 new ) 
	2) 类的内部创建对象 
	3) 向外暴露一个静态的公共方法。getInstance 
4) 代码实现 
package com.atzhu.singleton.type1; 

public class SingletonTest01 { 

	public static void main(String[] args) { 
		//测试 
		Singleton instance = Singleton.getInstance(); 
		Singleton instance2 = Singleton.getInstance(); 
		System.out.println(instance == instance2); // true 
		System.out.println("instance.hashCode=" + instance.hashCode()); 
		System.out.println("instance2.hashCode=" + instance2.hashCode()); 
	}
}


//饿汉式(静态变量) 
class Singleton { 

	//1. 构造器私有化, 外部能 new 
	private Singleton() { 

}

	//2.本类内部创建对象实例 
	private final static Singleton instance = new Singleton(); 


	//3. 提供一个公有的静态方法,返回实例对象 
	public static Singleton getInstance() { 
		return instance; 
	}
 }

优缺点说明:

	1) 优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。 
	2) 缺点:在类装载的时候就完成实例化,没有达到 Lazy Loading 的效果。如果从始至终从未使用过这个实例,则 会造成内存的浪费 
	3) 这种方式基于 classloder 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,在单例模式中大 多数都是调用 getInstance 方法,但是导致类装载的原因有很多种,因此不能确定有其他的方式(或者其他的静 态方法)导致类装载,这时候初始化 instance 就没有达到 lazy loading 的效果 
4) 结论:这种单例模式可用,可能造成内存浪费 

1.4 饿汉式(静态代码块)

代码演示: 
package com.atzhu.singleton.type2; 


public class SingletonTest02 { 


	public static void main(String[] args) { 
		//测试 
		Singleton instance = Singleton.getInstance(); 
		Singleton instance2 = Singleton.getInstance(); 
		System.out.println(instance == instance2); // true 
		System.out.println("instance.hashCode=" + instance.hashCode()); 
		System.out.println("instance2.hashCode=" + instance2.hashCode()); 
	}
}

//饿汉式(静态变量) 
class Singleton { 


//1. 构造器私有化, 外部能 new 
private Singleton() { 

}
 
//2.本类内部创建对象实例 
private static Singleton instance; 

static { // 在静态代码块中,创建单例对象 
instance = new Singleton(); 
}

//3. 提供一个公有的静态方法,返回实例对象 
	public static Singleton getInstance() { 
		return instance; 
	}
}

优缺点说明:

	1) 这种方式和上面的方式其实类似,只不过将类实例化的过程放在了静态代码块中,也是在类装载的时候,就执 行静态代码块中的代码,初始化类的实例。优缺点和上面是一样的。 
	2) 结论:这种单例模式可用,但是可能造成内存浪费 

1.5 懒汉式(线程不安全)

代码演示: 
package com.atzhu.singleton.type3; 

public class SingletonTest03 { 

	public static void main(String[] args) { 
		System.out.println("懒汉式 1 , 线程不安全~"); 
		Singleton instance = Singleton.getInstance(); 
		Singleton instance2 = Singleton.getInstance(); 
		System.out.println(instance == instance2); // true 
		System.out.println("instance.hashCode=" + instance.hashCode()); 
		System.out.println("instance2.hashCode=" + instance2.hashCode()); 
	}
}

class Singleton { 
	private static Singleton instance; 

	private Singleton() {} 

	//提供一个静态的公有方法,当使用到该方法时,才去创建 instance 
	//即懒汉式 
	public static Singleton getInstance() { 
		if(instance == null) { 
			instance = new Singleton(); 
		}
		return instance; 
	}
}

优缺点说明:

	1) 起到了 Lazy Loading 的效果,但是只能在单线程下使用。 
	2) 如果在多线程下,一个线程进入了 if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过 了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式 
	3) 结论:在实际开发中,不要使用这种方式. 

1.6 懒汉式(线程安全,同步方法)

代码演示: 
package com.atzhu.singleton.type4; 

public class SingletonTest04 { 

	public static void main(String[] args) { 
		System.out.println("懒汉式 2 , 线程安全~"); 
		Singleton instance = Singleton.getInstance(); 
		Singleton instance2 = Singleton.getInstance(); 
		System.out.println(instance == instance2); // true 
		System.out.println("instance.hashCode=" + instance.hashCode()); 
		System.out.println("instance2.hashCode=" + instance2.hashCode()); 
	}
}

	// 懒汉式(线程安全,同步方法) 
	class Singleton { 
		private static Singleton instance; 

		private Singleton() {} 

		//提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题 
	//即懒汉式 
	public static synchronized Singleton getInstance() { 
		if(instance == null) { 
			instance = new Singleton(); 
		}
		return instance; 
	}
}

优缺点说明:

	1) 解决了线程安全问题 
	2) 效率太低了,每个线程在想获得类的实例时候,执行 getInstance()方法都要进行同步。而其实这个方法只执行 一次实例化代码就够了,后面的想获得该类实例,直接 return 就行了。方法进行同步效率太低 
	3) 结论:在实际开发中,不推荐使用这种方式 

1.7 懒汉式(线程安全,同步代码块)

在这里插入图片描述

不推荐使用

1.8 双重检查

代码演示 
package com.atzhu.singleton.type6; 
 

public class SingletonTest06 { 

	public static void main(String[] args) { 
		System.out.println("双重检查"); 
		Singleton instance = Singleton.getInstance(); 
		Singleton instance2 = Singleton.getInstance(); 
		System.out.println(instance == instance2); // true 
		System.out.println("instance.hashCode=" + instance.hashCode()); 
		System.out.println("instance2.hashCode=" + instance2.hashCode()); 
	}
}

// 懒汉式(线程安全,同步方法) 
class Singleton { 
	private static volatile Singleton instance; 

	private Singleton() {} 

	//提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题 
	//同时保证了效率, 推荐使用 

	public static synchronized Singleton getInstance() { 
		if(instance == null) { 
			synchronized (Singleton.class) { 
				if(instance == null) { 
					instance = new Singleton(); 
				}
			}
		}
		return instance; 
	}
}

优缺点说明:

	1) Double-Check 概念是多线程开发中常使用到的,如代码中所示,我们进行了两次 if (singleton == null)检查,这 样就可以保证线程安全了。 
	2) 这样,实例化代码只用执行一次,后面再次访问时,判断 if (singleton == null),直接 return 实例化对象,也避 免的反复进行方法同步. 
	3) 线程安全;延迟加载;效率较高 
	4) 结论:在实际开发中,推荐使用这种单例设计模式 

1.9 静态内部类

代码演示: 
package com.atzhu.singleton.type7; 
 
public class SingletonTest07 { 

	public static void main(String[] args) { 
		System.out.println("使用静态内部类完成单例模式"); 
		Singleton instance = Singleton.getInstance(); 
		Singleton instance2 = Singleton.getInstance(); 
		System.out.println(instance == instance2); // true 
		System.out.println("instance.hashCode=" + instance.hashCode()); 
		System.out.println("instance2.hashCode=" + instance2.hashCode()); 
	}
}


// 静态内部类完成, 推荐使用 
class Singleton { 
	private static volatile Singleton instance; 

	//构造器私有化 
	private Singleton() {} 

	//写一个静态内部类,该类中有一个静态属性 Singleton 
	private static class SingletonInstance { 
		private static final Singleton INSTANCE = new Singleton(); 
	}

	//提供一个静态的公有方法,直接返回 SingletonInstance.INSTANCE 

	public static synchronized Singleton getInstance() { 

		return SingletonInstance.INSTANCE; 
	}
}

优缺点说明:

	1) 这种方式采用了类装载的机制来保证初始化实例时只有一个线程。 
	2) 静态内部类方式在 Singleton 类被装载时并不会立即实例化,而是在需要实例化时,调用 getInstance 方法,才 会装载 SingletonInstance 类,从而完成 Singleton 的实例化。 
	3) 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM 帮助我们保证了线程的安全性,在类进行 初始化时,别的线程是无法进入的。 
	4) 优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高 
5) 结论:推荐使用. 

1.10 枚举

代码演示 
package com.atzhu.singleton.type8; 

public class SingletonTest08 { 
	public static void main(String[] args) { 
		Singleton instance = Singleton.INSTANCE; Singleton instance2 = Singleton.INSTANCE; 
		System.out.println(instance == instance2); 

		System.out.println(instance.hashCode()); 
		System.out.println(instance2.hashCode()); 

		instance.sayOK(); 
	}
}

//使用枚举,可以实现单例, 推荐 
enum Singleton { 
	INSTANCE; //属性 
	public void sayOK() { 
		System.out.println("ok~"); 
	}
}

优缺点说明:

	1) 这借助 JDK1.5 中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建 新的对象。 
	2) 这种方式是 Effective Java 作者 Josh Bloch 提倡的方式 
3) 结论:推荐使用 

1.11 单例模式在 JDK 应用的源码分析

  1. 单例模式在 JDK 应用的源码分析

    1) 我们 JDK 中,java.lang.Runtime 就是经典的单例模式(饿汉式) 
    2) 代码分析+Debug 源码+代码说明
    

    在这里插入图片描述

  2. 单例模式注意事项和细节说明

    1) 单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使 用单例模式可以提高系统性能 
    2) 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用 new 
    3) 单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(**即:重量级 对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session 工厂等**)
    

二· 工厂模式

2.1 简单 工厂模 式

  1. 看一个具体的需求
    看一个披萨的项目:要便于披萨种类的扩展,要便于维护

    1) 披萨的种类很多(比如 GreekPizz、CheesePizz 等) 
    2) 披萨的制作有 prepare,bake, cut, box 
    3) 完成披萨店订购功能。 
    
  2. 使用传统的方式来完成

    1) 思路分析(类图)
    

在这里插入图片描述

编写 OrderPizza.java 去订购需要的各种 Pizza
2)看代码
public class OrderPizza { 
	// 构造器 
	public OrderPizza() { 
		Pizza pizza = null; 
		String orderType; // 订购披萨的类型 
		do { 
			orderType = getType(); 
			if (orderType.equals("greek")) { 
				pizza = new GreekPizza(); 
				pizza.setName(" 希腊披萨 "); 
			} else if (orderType.equals("cheese")) { 
				pizza = new CheesePizza(); 
				pizza.setName(" 奶酪披萨 "); 
			} else if (orderType.equals("pepper")) { 
				pizza = new PepperPizza(); 
				pizza.setName("胡椒披萨"); 
			} else { 
				break; 
			}
			//输出 pizza 制作过程 
			pizza.prepare(); 
			pizza.bake(); 
			pizza.cut(); pizza.box(); 
		} while (true); 
	}
}
  1. 传统的方式的优缺点

    1) 优点是比较好理解,简单易操作。 
    2) 缺点是违反了设计模式的 ocp 原则,即对扩展开放,对修改关闭。即当我们给类增加新功能的时候,尽量不修 改代码,或者尽可能少修改代码. 
    3) 比如我们这时要新增加一个 Pizza 的种类(Pepper 披萨),我们需要做如下修改. 如果我们增加一个 Pizza 类,只要是订购 Pizza 的代码都需要修改.
    

在这里插入图片描述

4)改进的思路分析

	分析:修改代码可以接受,但是如果我们在其它的地方也有创建 Pizza 的代码,就意味着,也需要修改,而创建 Pizza 的代码,往往有多处。 
	思路: 创建 Pizza 对象封装到一个类中, 样我们有新的 Pizza 种类时, 需要修改该类就可, 它有创建到 Pizza 把	这	只	其
对象的代码就不需要修改了.-> 简单工厂模式
  1. 基本介绍

    1) 简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品 类的实例。简单工厂模式是工厂模式家族中最简单实用的模式 
    2) 简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码) 
    3) 在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式. 
    
  2. 使用简单工厂模式

    1) 简单工厂模式的设计方案: 定义一个可以实例化 Pizaa 对象的类,封装创建对象的代码。
    

在这里插入图片描述

2)看代码实例
package com.atzhu.factory.simplefactory.pizzastore.order; 

import com.atzhu.factory.simplefactory.pizzastore.pizza.CheesePizza; 
import com.atzhu.factory.simplefactory.pizzastore.pizza.GreekPizza; import com.atzhu.factory.simplefactory.pizzastore.pizza.PepperPizza; 
import com.atzhu.factory.simplefactory.pizzastore.pizza.Pizza; 


//简单工厂类 
public class SimpleFactory { 


	//更加 orderType 返回对应的 Pizza 对象 
	public Pizza createPizza(String orderType) { 


		Pizza pizza = null; 

		System.out.println("使用简单工厂模式"); 
		if (orderType.equals("greek")) { 
			pizza = new GreekPizza(); 
			pizza.setName(" 希腊披萨 "); 
		} else if (orderType.equals("cheese")) { 
			pizza = new CheesePizza(); 
			pizza.setName(" 奶酪披萨 "); 
		} else if (orderType.equals("pepper")) { 
			pizza = new PepperPizza(); 
			pizza.setName("胡椒披萨"); 
		}
		return pizza; 
	}
	//简单工厂模式 也叫 静态工厂模式 
	public static Pizza createPizza2(String orderType) { 

		Pizza pizza = null; 

		System.out.println("使用简单工厂模式 2"); 
		if (orderType.equals("greek")) { 
			pizza = new GreekPizza(); 
			pizza.setName(" 希腊披萨 "); 
		} else if (orderType.equals("cheese")) { 
			pizza = new CheesePizza(); 
			pizza.setName(" 奶酪披萨 "); 
		} else if (orderType.equals("pepper")) { 
			pizza = new PepperPizza(); 
			pizza.setName("胡椒披萨"); 
		}

		return pizza; 
	}
}


//OrderPizza.java 
package com.atzhu.factory.simplefactory.pizzastore.order; 


import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import com.atzhu.factory.simplefactory.pizzastore.pizza.Pizza; 

public class OrderPizza { 


	// 构造器  
//public OrderPizza() { 
//Pizza pizza = null; 
//String orderType; // 订购披萨的类型 
//do { 
//orderType = getType(); 
//if (orderType.equals("greek")) { 
//pizza = new GreekPizza(); 
//pizza.setName(" 希腊披萨 "); 
//} else if (orderType.equals("cheese")) { 
//pizza = new CheesePizza(); 
//pizza.setName(" 奶酪披萨 "); 
//} else if (orderType.equals("pepper")) { 
//pizza = new PepperPizza(); 
//pizza.setName("胡椒披萨"); 
//} else { 
//break; 
//}
 
 
// 	//输出 pizza 制作过程 
// 	pizza.prepare(); 
// 	pizza.bake(); 
// 	pizza.cut(); 
// 	pizza.box(); 
// 
// 	} while (true); 
// 	}
 

	//定义一个简单工厂对象 
	SimpleFactory simpleFactory; 
	Pizza pizza = null; 


	//构造器 
	public OrderPizza(SimpleFactory simpleFactory) { 
		setFactory(simpleFactory); 
	}

	public void setFactory(SimpleFactory simpleFactory) { 
		String orderType = ""; //用户输入的 

		this.simpleFactory = simpleFactory; //设置简单工厂对象 

		do { 
			orderType = getType(); 
			pizza = this.simpleFactory.createPizza(orderType); 

			//输出 pizza 
			if(pizza != null) { //订购成功 
				pizza.prepare(); 
				pizza.bake(); 
				pizza.cut(); 
				pizza.box(); 
			} else { 
				System.out.println(" 订购披萨失败 "); 
				break; 
			}
		}while(true); 
	}


	// 写一个方法,可以获取客户希望订购的披萨种类 
	private String getType() { 
	try { 
		BufferedReader strin = new BufferedReader(new InputStreamReader(System.in)); 
		System.out.println("input pizza 种类:"); 
		String str = strin.readLine(); 
		return str; 
	} catch (IOException e) { 
		e.printStackTrace(); 
		return ""; 
	}
}

}

2.2 工厂方法模式

  1. 看一个新的需求

    披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪 pizza、北京的胡椒 pizza 或 者是伦敦的奶酪 pizza、伦敦的胡椒 pizza。
    
  2. 思路1

    使用简单工厂模式,创建不同的简单工厂类,比如 BJPizzaSimpleFactory、LDPizzaSimpleFactory 等等.从当前 这个案例来说,也是可以的,但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好
    
  3. 思路 2

    使用工厂方法模式 
    
  4. 工厂方法模式介绍

    1) 工厂方法模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。 
    2) 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例 化推迟到子类。 
    
  5. 工厂方法模式应用案例

    1) 披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪 pizza、北京的胡椒 pizza 或 者是伦敦的奶酪 pizza、伦敦的胡椒 pizza
    2) 思路分析图解
    

在这里插入图片描述

3)看代码实现
//OrderPizza.java 类 

package com.atzhu.factory.factorymethod.pizzastore.order; 



import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 



import com.atzhu.factory.factorymethod.pizzastore.pizza.Pizza; 


public abstract class OrderPizza { 


	//定义一个抽象方法,createPizza , 让各个工厂子类自己实现 
	abstract Pizza createPizza(String orderType); 


	// 构造器 
	public OrderPizza() { 
		Pizza pizza = null; 
		String orderType; // 订购披萨的类型 
		do { 
			orderType = getType(); 
			pizza = createPizza(orderType); //抽象方法,由工厂子类完成 
			//输出 pizza 制作过程 
			pizza.prepare(); 
			pizza.bake(); 
			pizza.cut(); 
			pizza.box(); 

		} while (true); 
	}

	// 写一个方法,可以获取客户希望订购的披萨种类 
	private String getType() { 
		try { 
			BufferedReader strin = new BufferedReader(new InputStreamReader(System.in)); 
			System.out.println("input pizza 种类:"); 
			String str = strin.readLine(); 
			return str; 
		} catch (IOException e) { 
			e.printStackTrace(); 
			return ""; 
		}
	}
}


package com.atzhu.factory.factorymethod.pizzastore.order; 



import com.atzhu.factory.factorymethod.pizzastore.pizza.BJCheesePizza; 
import com.atzhu.factory.factorymethod.pizzastore.pizza.BJPepperPizza; 
import com.atzhu.factory.factorymethod.pizzastore.pizza.Pizza; 


public class BJOrderPizza extends OrderPizza { 


	@Override 
	Pizza createPizza(String orderType) { 


		Pizza pizza = null; 
		if(orderType.equals("cheese")) { 
			pizza = new BJCheesePizza(); 
		} else if (orderType.equals("pepper")) { 
			pizza = new BJPepperPizza(); 
		}
		// TODO Auto-generated method stub 
		return pizza; 
	}
 
}


package com.atzhu.factory.factorymethod.pizzastore.order; 

import com.atzhu.factory.factorymethod.pizzastore.pizza.BJCheesePizza; 
import com.atzhu.factory.factorymethod.pizzastore.pizza.BJPepperPizza; import com.atzhu.factory.factorymethod.pizzastore.pizza.LDCheesePizza; import com.atzhu.factory.factorymethod.pizzastore.pizza.LDPepperPizza; 
import com.atzhu.factory.factorymethod.pizzastore.pizza.Pizza; 



public class LDOrderPizza extends OrderPizza { 

	@Override 
	Pizza createPizza(String orderType) { 

		Pizza pizza = null; 
		if(orderType.equals("cheese")) { 
			pizza = new LDCheesePizza(); 
		} else if (orderType.equals("pepper")) { 
			pizza = new LDPepperPizza(); 
		}
		// TODO Auto-generated method stub 
		return pizza; 
	}
}

2.3 抽象 工厂模 式

  1. 基本介绍

    1) 抽象工厂模式:定义了一个 interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类 
    2) 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。 
    3) 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。 
    4) 将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应 的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。 
    5) 类图
    

在这里插入图片描述

  1. 抽象工厂模式应用实例

    使用抽象工厂模式来完成披萨项目.
    
package com.atzhu.factory.absfactory.pizzastore.order; 

import com.atzhu.factory.absfactory.pizzastore.pizza.Pizza; 


//一个抽象工厂模式的抽象层(接口) 
public interface AbsFactory { 
	//让下面的工厂子类来 具体实现 
	public Pizza createPizza(String orderType); 
}



package com.atzhu.factory.absfactory.pizzastore.order; 



import com.atzhu.factory.absfactory.pizzastore.pizza.BJCheesePizza; 
import com.atzhu.factory.absfactory.pizzastore.pizza.BJPepperPizza; 
import com.atzhu.factory.absfactory.pizzastore.pizza.Pizza; 



//这是工厂子类 
public class BJFactory implements AbsFactory { 



	@Override 
	public Pizza createPizza(String orderType) { 
		System.out.println("~使用的是抽象工厂模式~"); 
		// TODO Auto-generated method stub 
		Pizza pizza = null; 
		if(orderType.equals("cheese")) { 
			pizza = new BJCheesePizza(); 
		} else if (orderType.equals("pepper")){ 
			pizza = new BJPepperPizza(); 
		}
			return pizza; 
	}
}



package com.atzhu.factory.absfactory.pizzastore.order; 

import com.atzhu.factory.absfactory.pizzastore.pizza.LDCheesePizza; 
import com.atzhu.factory.absfactory.pizzastore.pizza.LDPepperPizza; 
import com.atzhu.factory.absfactory.pizzastore.pizza.Pizza; 
 


public class LDFactory implements AbsFactory { 



	@Override 
	public Pizza createPizza(String orderType) { 
		System.out.println("~使用的是抽象工厂模式~"); 
		Pizza pizza = null; 
		if (orderType.equals("cheese")) { 
			pizza = new LDCheesePizza(); 
		} else if (orderType.equals("pepper")) { 
			pizza = new LDPepperPizza(); 
		}
		return pizza; 
	}
}


//OrderPizza.java 
package com.atzhu.factory.absfactory.pizzastore.order; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 



import com.atzhu.factory.absfactory.pizzastore.pizza.Pizza; 


public class OrderPizza { 


	AbsFactory factory; 


	// 构造器 
	public OrderPizza(AbsFactory factory) { 
		setFactory(factory); 
	}


	private void setFactory(AbsFactory factory) { 
		Pizza pizza = null; 
		String orderType = ""; // 用户输入 
		this.factory = factory; 
		do { 
			orderType = getType(); 
			// factory 可能是北京的工厂子类,也可能是伦敦的工厂子类 
			pizza = factory.createPizza(orderType); 
			if (pizza != null) { // 订购 ok 
				pizza.prepare(); 
				pizza.bake(); 
				pizza.cut(); 
				pizza.box(); 
			} else { 
				System.out.println("订购失败"); 
				break; 
			}
		} while (true); 
	}

	// 写一个方法,可以获取客户希望订购的披萨种类 
	private String getType() { 
		try { 
			BufferedReader strin = new BufferedReader(new InputStreamReader(System.in)); 
			System.out.println("input pizza 种类:"); 
			String str = strin.readLine(); 
			return str; 
		} catch (IOException e) { 
			e.printStackTrace(); 
			return ""; 
		}
	}
}

2.4 工厂模式在 JDK-Calendar 应用的源码分析

1) JDK 中的 Calendar 类中,就使用了简单工厂模式 
2) 源码分析+Debug 源码+说明
源码部分
package com.atzhu.jdk; 


import java.util.Calendar; 


public class Factory { 


	public static void main(String[] args) { 
		// TODO Auto-generated method stub // getInstance 是 Calendar 静态方法 
		Calendar cal = Calendar.getInstance(); 
		// 注意月份下标从 0 开始,所以取月份要+1 
		System.out.println("年:" + cal.get(Calendar.YEAR)); 
		System.out.println("月:" + (cal.get(Calendar.MONTH) + 1)); 
		System.out.println("日:" + cal.get(Calendar.DAY_OF_MONTH)); 
		System.out.println("时:" + cal.get(Calendar.HOUR_OF_DAY)); 
		System.out.println("分:" + cal.get(Calendar.MINUTE)); System.out.println("秒:" + cal.get(Calendar.SECOND)); 

	}


}


//Calendar.java 
public static Calendar getInstance() 
{
	return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT)); 
}

private static Calendar createCalendar(TimeZone zone, 
Locale aLocale) //根据 TimeZone zone, locale 创建对应的实例 
{
	CalendarProvider provider = 
LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale) 
.getCalendarProvider(); 
	if (provider != null) { 
		try { 
			return provider.getInstance(zone, aLocale); 
		} catch (IllegalArgumentException iae) { 
		// fall back to the default instantiation 
	}
}

	Calendar cal = null; 


	if (aLocale.hasExtensions()) { 
		String caltype = aLocale.getUnicodeLocaleType("ca"); 
		if (caltype != null) { 
			switch (caltype) { 
			case "buddhist": 
				cal = new BuddhistCalendar(zone, aLocale); 
				break; 
			case "japanese": 
				cal = new JapaneseImperialCalendar(zone, aLocale); 
				break; 
			case "gregory": 
				cal = new GregorianCalendar(zone, aLocale); 
				break; 
			}
		}
	}
 
	if (cal == null) { 
		// If no known calendar type is explicitly specified, // 
		perform the traditional way to create a Calendar: 
		// create a BuddhistCalendar for th_TH locale, 
		// a JapaneseImperialCalendar for ja_JP_JP locale, or // a 
		GregorianCalendar for any other locales. 
		// NOTE: The language, country and variant strings are interned. 
		if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") { 
			cal = new BuddhistCalendar(zone, aLocale); 
		} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja" 
&& aLocale.getCountry() == "JP") { 
			cal = new JapaneseImperialCalendar(zone, aLocale); 
		} else { 
			cal = new GregorianCalendar(zone, aLocale); 
		}
	}
	return cal; 
}

2.5 工厂模式小结

1) 工厂模式的意义 
	将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项 目的扩展和维护性。 

2) 三种工厂模式 (简单工厂模式、工厂方法模式、抽象工厂模式) 
3) 设计模式的依赖抽象原则 
	创建对象实例时,不要直接 new 类, 而是把这个 new 类的动作放在一个工厂的方法中,并返回。有的书上说, 变量不要直接持有具体类的引用。 
	不要让类继承具体类,而是继承抽象类或者是实现 interface(接口) 
	不要覆盖基类中已经实现的方法。

三· 原型模式

3.1 克隆羊问题

现在有一只羊 tom,姓名为: tom, 年龄为:1,颜色为:白色,请编写程序创建和 tom 羊 属性完全相同的 10 只羊。 

3.2 传统方式解决克隆羊问题

1) 思路分析(图解)

在这里插入图片描述

2)看代码实现
package com.atzhu.prototype; 


public class Client { 

	public static void main(String[] args) { 
		// TODO Auto-generated method stub 
		//传统的方法 
		Sheep sheep = new Sheep("tom", 1, "白色"); 
		Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor()); 
		Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor()); 
		Sheep sheep4 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor()); 
		Sheep sheep5 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor()); 
//.... 

		System.out.println(sheep); 
		System.out.println(sheep2); 
		System.out.println(sheep3); 
		System.out.println(sheep4); 
		System.out.println(sheep5); //... 
	}
}

3.3 传统的方式的优缺点

	1) 优点是比较好理解,简单易操作。 
	2) 在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低 
	3) 总是需要重新初始化对象,而不是动态地获得对象运行时的状态, 不够灵活 
	4) 改进的思路分析 
思路:Java 中 Object 类是所有类的根类,Object 类提供了一个 clone()方法,该方法可以将一个 Java 对象复制 但	该原型模式 一份, 是需要实现 clone 的 Java 类必须要实现一个接口 Cloneable, 接口表示该类能够复制且具有复制的能力 => 

3.4 原型模式-基本介绍

基本介绍 
	1) 原型模式(Prototype 模式)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象 
	2) 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节 
	3) 工作原理是:通过将一个原型对象传给那个要发动创建的对象, 个要发动创建的对象通过请求原型对象拷贝它 这们自己来实施创建,即 对象.clone() 
	4) 形象的理解:孙大圣拔出猴毛, 变出其它孙大圣 

3.5 原型模式原理结构图-uml类图

在这里插入图片描述

原理结构图说明
	1) Prototype : 原型类,声明一个克隆自己的接口 
	2) ConcretePrototype: 具体的原型类, 实现一个克隆自己的操作 
	3) Client: 让一个原型对象克隆自己,从而创建一个新的对象(属性一样)

3.6 原型模式解决克隆羊问题的应用 实例

使用原型模式改进传统方式,让程序具有更高的效率和扩展性。 

代码实现

package com.atzhu.prototype.improve; 

public class Sheep implements Cloneable { 
	private String name; 
	private int age; 
	private String color; 
	private String address = "蒙古羊"; 
	public Sheep friend; //是对象, 克隆是会如何处理, 默认是浅拷贝 
	public Sheep(String name, int age, String color) { 
		super();
		this.name = name; 
		this.age = age; 
		this.color = color; 
	}
	public String getName() { 
		return name; 
	}
	public void setName(String name) { 
		this.name = name; 
	}
	public int getAge() { 
		return age; 
	}
	public void setAge(int age) { 

		this.age = age; 
	}
	public String getColor() { 
		return color; 
	}
	public void setColor(String color) { 
		this.color = color; 
	}
 

	@Override 
	public String toString() { 
		return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", address=" + address + "]"; 
	}
	//克隆该实例,使用默认的 clone 方法来完成 
	@Override 
	protected Object clone() 	{
		Sheep sheep = null; 
		try { 
			sheep = (Sheep)super.clone(); 
		} catch (Exception e) { 
			// TODO: handle exception 
			System.out.println(e.getMessage()); 
		}

		// TODO Auto-generated method stub 
		return sheep; 
	}

}


package com.atzhu.prototype.improve; 
 
public class Client { 


	public static void main(String[] args) { 
		System.out.println("原型模式完成对象的创建"); 
		// TODO Auto-generated method stub 
		Sheep sheep = new Sheep("tom", 1, "白色"); 

		sheep.friend = new Sheep("jack", 2, "黑色"); 


		Sheep sheep2 = (Sheep)sheep.clone(); //克隆 
		Sheep sheep3 = (Sheep)sheep.clone(); //克隆 
		Sheep sheep4 = (Sheep)sheep.clone(); //克隆 
		Sheep sheep5 = (Sheep)sheep.clone(); //克隆 


		System.out.println("sheep2 =" + sheep2 + "sheep2.friend=" + sheep2.friend.hashCode()); 
		System.out.println("sheep3 =" + sheep3 + "sheep3.friend=" + sheep3.friend.hashCode()); 
		System.out.println("sheep4 =" + sheep4 + "sheep4.friend=" + sheep4.friend.hashCode()); 
		System.out.println("sheep5 =" + sheep5 + "sheep5.friend=" + sheep5.friend.hashCode()); 
	}
}

3.7 原型模式在 Spring 框架中源码分析

1) Spring 中原型 bean 的创建,就是原型模式的应用 
2) 代码分析+Debug 源码

在这里插入图片描述

3.8 深入讨论-浅拷贝和深拷贝

  1. 浅拷贝的介绍

    1) 对于数据类型是基本数据类型的成员变量, 拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。 浅
    2) 对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,
    	那么浅拷贝会进行 引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成 员变量都指向同一个实例。
    	在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值 
    3) 前面我们克隆羊就是浅拷贝 
    4) 浅拷贝是使用默认的 clone()方法来实现 
    sheep = (Sheep) super.clone(); 
    
  2. 深拷贝基本介绍

    1) 复制对象的所有基本数据类型的成员变量值 
    2) 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象 可达的所有对象。
    	也就是说,对象进行深拷贝要对整个对象(包括对象的引用类型)进行拷贝 
    3) 深拷贝实现方式 1:重写 clone 方法来实现深拷贝 
    4) 深拷贝实现方式 2:通过对象序列化实现深拷贝(推荐) 
    

3.9 深拷贝应用实例

1) 使用 重写 clone 方法实现深拷贝 
2) 使用序列化来实现深拷贝 
3) 代码演示 
package com.atzhu.prototype.deepclone; 


import java.io.Serializable; 


public class DeepCloneableTarget implements Serializable, Cloneable { 


	/ ** 
	*
	*/ 
	private static final long serialVersionUID = 1L; 


	private String cloneName; 


	private String cloneClass; 


	//构造器 
	public DeepCloneableTarget(String cloneName, String cloneClass) { 
		this.cloneName = cloneName; 
		this.cloneClass = cloneClass; 
	}


	//因为该类的属性,都是 String , 因此我们这里使用默认的 clone 完成即可 
	@Override 
	protected Object clone() throws CloneNotSupportedException { 
		return super.clone(); 
	}
}




//... 
package com.atzhu.prototype.deepclone; 



import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 

import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.io.Serializable; 


public class DeepProtoType implements Serializable, Cloneable{ 


	public String name; //String 属性 
	public DeepCloneableTarget deepCloneableTarget;// 引用类型 
	public DeepProtoType() { 
		super(); 
	}


	//深拷贝 - 方式 1 使用 clone 方法 
	@Override 
	protected Object clone() throws CloneNotSupportedException { 


		Object deep = null; 
		//这里完成对基本数据类型(属性)和 String 的克隆 
		deep = super.clone(); 
		//对引用类型的属性,进行单独处理 
		DeepProtoType deepProtoType = (DeepProtoType)deep; 
		deepProtoType.deepCloneableTarget 	= (DeepCloneableTarget)deepCloneableTarget.clone(); 


		// TODO Auto-generated method stub 
		return deepProtoType; 
	}


	//深拷贝 - 方式 2 通过对象的序列化实现 (推荐) 
	public Object deepClone() { 


		//创建流对象 
		ByteArrayOutputStream bos = null; 
		ObjectOutputStream oos = null; 
		ByteArrayInputStream bis = null; 
		ObjectInputStream ois = null; 

		try { 


			//序列化 
			bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bos); 
			oos.writeObject(this); //当前这个对象以对象流的方式输出 


			//反序列化 
			bis = new ByteArrayInputStream(bos.toByteArray()); 
			ois = new ObjectInputStream(bis); 
			DeepProtoType copyObj = (DeepProtoType)ois.readObject(); 

			return copyObj; 

		} catch (Exception e) { 
			// TODO: handle exception 
			e.printStackTrace(); 
			return null; 
		} finally { 
			//关闭流 
			try { 
				bos.close(); 
				oos.close(); 
				bis.close(); 
				ois.close(); 
			} catch (Exception e2) { 
				// TODO: handle exception 
				System.out.println(e2.getMessage()); 
			}
		}
	}
}



//Client.java 
package com.atzhu.prototype.deepclone; 


public class Client { 

	public static void main(String[] args) throws Exception { 
		// TODO Auto-generated method stub 
		DeepProtoType p = new DeepProtoType(); 
		p.name = "宋江"; 
		p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛"); 


		//方式 1 完成深拷贝 
// 		DeepProtoType p2 = (DeepProtoType) p.clone(); 
// 
// 		System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode()); 
// 		System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode()); 

		//方式 2 完成深拷贝 
	DeepProtoType p2 = (DeepProtoType) p.deepClone(); 

	System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode()); 
	System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode()); 

	}
}

3.10 原型模式的注意事项和细节

1) 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率 
2) 不用重新初始化对象,而是动态地获得对象运行时的状态 
3) 如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码 
4) 在实现深克隆的时候可能需要比较复杂的代码 
5) 缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改 其源代码,违背了 ocp 原则,这点请各位注意.

四· 建造者模式

4.1 盖房项目需求

1) 需要建房子:这一过程为打桩、砌墙、封顶 
2) 房子有各种各样的,比如普通房,高楼,别墅,各种房子的过程虽然一样,但是要求不要相同的. 3) 请编写程序,完成需求. 

4.2 传统方式解决盖房需求

1) 思路分析(图解)

在这里插入图片描述

2)看代码演示
package com.atzhu.builder; 


public abstract class AbstractHouse { 

	//打地基 
	public abstract void buildBasic(); 
	//砌墙 
	public abstract void buildWalls(); 
	//封顶 
	public abstract void roofed(); 

	public void build() { 
		buildBasic(); 
		buildWalls(); 
		roofed(); 
	}
}


package com.atzhu.builder; 


public class CommonHouse extends AbstractHouse { 

	@Override 
	public void buildBasic() { 
		// TODO Auto-generated method stub 
		System.out.println(" 普通房子打地基 "); 
	}


	@Override 
	public void buildWalls() { 
		// TODO Auto-generated method stub 
		System.out.println(" 普通房子砌墙 "); 
	}

	@Override 
	public void roofed() { 
		// TODO Auto-generated method stub 
		System.out.println(" 普通房子封顶 "); 
	}
}


package com.atzhu.builder; 

public class Client { 


	public static void main(String[] args) { 
		// TODO Auto-generated method stub 
		CommonHouse commonHouse = new CommonHouse(); 
		commonHouse.build(); 
	}
}

4.3 传统方式的问题分析

1) 优点是比较好理解,简单易操作。 
2) 设计的程序结构,过于简单,没有设计缓存层对象,程序的扩展和维护不好. 也就是说,这种设计方案,把产 品(即:房子) 和 创建产品的过程(即:建房子流程) 封装在一起,耦合性增强了。
3) 解决方案:将产品和产品建造过程解耦 => 建造者模式. 

4.4 建造者模式基本介绍

基本介绍 
	1) 建造者模式(Builder Pattern) 又叫生成器模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出 来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。 
	2) 建造者模式 是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们, 用户不需要知道内部的具体构建细节。 

4.5 建造者模式的四个角色

1) Product(产品角色): 一个具体的产品对象。 
2) Builder(抽象建造者): 创建一个 Product 对象的各个部件指定的 接口/抽象类。 
3) ConcreteBuilder(具体建造者): 实现接口,构建和装配各个部件。 
4) Director(指挥者): 构建一个使用 Builder 接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作 用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。 

4.6 建造者模式原理类图

在这里插入图片描述

4.7 建造者模式解决盖房需求应用实例

1) 需要建房子:这一过程为打桩、砌墙、封顶。不管是普通房子也好,别墅也好都需要经历这些过程,下面我们 使用建造者模式(Builder Pattern)来完成 
2) 思路分析图解(类图)

在这里插入图片描述

3)代码实现
package com.atzhu.builder.improve; 


public class Client { 
	public static void main(String[] args) { 


		//盖普通房子 
		CommonHouse commonHouse = new CommonHouse(); 
		//准备创建房子的指挥者 
		HouseDirector houseDirector = new HouseDirector(commonHouse); 


		//完成盖房子,返回产品(普通房子) 
		House house = houseDirector.constructHouse(); 


		//System.out.println("输出流程"); 

		System.out.println("--------------------------"); 
		//盖高楼 
		HighBuilding highBuilding = new HighBuilding(); 
		//重置建造者 
		houseDirector.setHouseBuilder(highBuilding); 
		//完成盖房子,返回产品(高楼) 
		houseDirector.constructHouse(); 
	}
}
 


package com.atzhu.builder.improve; 


public class CommonHouse extends HouseBuilder { 


	@Override 
	public void buildBasic() { 
		// TODO Auto-generated method stub 
		System.out.println(" 普通房子打地基 5 米 "); 
	}


	@Override 
	public void buildWalls() { 
		// TODO Auto-generated method stub 
		System.out.println(" 普通房子砌墙 10cm "); 
	}


	@Override 
	public void roofed() { 
		// TODO Auto-generated method stub 
		System.out.println(" 普通房子屋顶 "); 
	}
}



package com.atzhu.builder.improve; 


public class HighBuilding extends HouseBuilder { 


	@Override 
	public void buildBasic() { 
		// TODO Auto-generated method stub 
		System.out.println(" 高楼的打地基 100 米 "); 
	}


	@Override 
	public void buildWalls() { 
		// TODO Auto-generated method stub 
		System.out.println(" 高楼的砌墙 20cm "); 
	}


	@Override 
	public void roofed() { 
		// TODO Auto-generated method stub 
		System.out.println(" 高楼的透明屋顶 "); 
	}
}




package com.atzhu.builder.improve; 



//产品->Product 
public class House { 
	private String baise; private String wall; 
	private String roofed; 
	public String getBaise() { 
		return baise; 
	}
	public void setBaise(String baise) { 
		this.baise = baise; 
	}
	public String getWall() { 
		return wall; 
	}
	public void setWall(String wall) { 
		this.wall = wall; 
	}
	public String getRoofed() { 
		return roofed; 
	}
	public void setRoofed(String roofed) { 
		this.roofed = roofed; 
	}
}



package com.atzhu.builder.improve; 
 

// 抽象的建造者 
public abstract class HouseBuilder { 


	protected House house = new House(); 


	//将建造的流程写好, 抽象的方法 
	public abstract void buildBasic(); public abstract void buildWalls(); 
	public abstract void roofed(); 
	//建造房子好, 将产品(房子) 返回 
	public House buildHouse() { 
		return house; 
	}
}



package com.atzhu.builder.improve; 


//指挥者,这里去指定制作流程,返回产品 
public class HouseDirector { 


	HouseBuilder houseBuilder = null; 


	//构造器传入 houseBuilder 
	public HouseDirector(HouseBuilder houseBuilder) { 
		this.houseBuilder = houseBuilder; 
	}


	//通过 setter 传入 houseBuilder 
	public void setHouseBuilder(HouseBuilder houseBuilder) { 
		this.houseBuilder = houseBuilder; 
	}


	//如何处理建造房子的流程,交给指挥者 
	public House constructHouse() { 
		houseBuilder.buildBasic(); 
		houseBuilder.buildWalls(); 
		houseBuilder.roofed(); 
		return houseBuilder.buildHouse(); 
	}
}

4.8 建 造 者 模 式 在 J DK 的 应 用 和 源 码 分 析

1) java.lang.StringBuilder 中的建造者模式 
2) 代码说明+Debug 源码

在这里插入图片描述

3)源码中建造者模式角色分析
	Appendable 接口定义了多个 append 方法(抽象方法), 即 Appendable 为抽象建造者, 定义了抽象方法 
	AbstractStringBuilder 实现了 Appendable 接口方法,这里的 AbstractStringBuilder 	已经是建造者, 只是不能 实例化 
	StringBuilder 即充当了指挥者角色,同时充当了具体的建造者,建造方法的实现是由 AbstractStringBuilder 完 成, 而 StringBuilder 继承了 AbstractStringBuilder 

4.9 建造者模式的注意事项和细节

1) 客户端(使用程序)不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可 以创建不同的产品对象 
2) 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具 体建造者, 用户使用不同的具体建造者即可得到不同的产品对象 
3) 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰, 也更方便使用程序来控制创建过程 
4) 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合 "开闭 原则" 
5) 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使 用建造者模式,因此其使用范围受到一定的限制。 
6) 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,因 此在这种情况下,要考虑是否选择建造者模式. 
7) 抽象工厂模式 VS 建造者模式 
	抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采 用抽象工厂模式不需要关心构建过程,只关心什么产品由什么工厂生产即可。
	而建造者模式则是要求按照指定 的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朱yoyo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值