目录
UML类图
1、用于描述系统中的类(对象)本身的组成和类(对象)之间的各种静态关系。
2、类之间的关系:依赖、泛化(继承)、实现、关联、聚合与组合。
依赖关系:只要在类中使用了对方
class A{
B b;
public void testOne(){
C c = new C();
}
}
class B{}
class C{}
小结:在类的成员属性,方法参数,方法返回值,类的方法中使用了,都属于本类依赖某类
泛化关系:就是继承关系,属于特殊的依赖关系
实现关系:接口和实现类
关联关系(Association ):类与类之间的联系,属于特殊的依赖关系
关联具有到航性:即双向关系或单项关系
关系具有多重性:一对一,一对多,多对多
属于成员变量层面的依赖
//单项一对一关系
/**
* 人 实体
*/
class Person{
IDCard id;
}
/**
* 身份证 实体
*/
class IDCard{}
//双向一对一关系
class Person{
IDCard id;
}
class IDCard{
Person person;//该身份证属于某人
}
聚合关系(Aggregation):表示整体和部分的关系,整体与部分可以分开。聚合关系是关联关系的特例,具有关联的到航性与多重性。
class Computer{
private Mouse mouse;
private Monitor monitor;
}
class Mouse{}
class Monitor{}
组合关系(composition):描述整体与部分的关系,但是整体与部分不可分割。
将上述电脑,鼠标,显示器不可分离进行升级,便可成为组合关系
class Computer{
private Mouse mouse = new Mouse();
private Monitor monitor = new Monitor();
}
class Mouse{}
class Monitor{}
拓展: 级联删除属于组合关系
Example:删除一个人的信息时,删除他的身份证信息。
设计模式类型
1、创建型模式:单例,抽象工厂,原型,建造者,工厂
单例:当前系统类实例只能有一个
原型:对象的克隆,深 or 浅拷贝
2、结构型模式:适配器,桥接,装饰,组合,外观,享元,代理
3、行为模式:模板方案,命令,解释器,状态,策略,职责链(责任链)
方法角度合理性设计
单例模式
所谓的单例模式,就是采用一定的方法保证在整个系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)
单例模式八种方式:
1、饿汉式(静态常量)
//饿汉式(静态变量)
class Singleton{
//静态变量实例化
private static final Singleton instance = new Singleton();
//构造器私有化
private Singleton(){}
//提供一个公开的静态方法,获取实例对象
public static Singleton getInstance(){
return instance;
}
}
优点:类加载时完成实例化,避免线程同步问题。
缺点:在类加载时完成实例化,没有达到懒加载效果,如果系统中未使用该实例对象,会造成内存浪费。
拓展:
线程同步是指在多线程环境下,通过一些机制来保证多个线程之间的数据访问顺序和结果的正确性。在并发编程中,如果多个线程同时访问共享资源,可能会导致数据不一致或者出现其他问题,因此需要采取同步措施来确保线程安全。
线程安全是指在多线程环境下,程序的执行结果与单线程环境下的执行结果一致,不会出现数据竞争、死锁、活锁等问题。在多线程环境下,如果能够保证多个线程同时访问共享资源时不会发生冲突或者竞态条件,就可以称之为线程安全。
2、饿汉式(静态代码块)
//饿汉式(静态代码块)
class Singleton{
//静态变量
private static final Singleton instance;
//静态代码块实例化
static {
instance = new Singleton();
}
//构造器私有化
private Singleton(){}
//提供一个公开的静态方法,获取实例对象
public static Singleton getInstance(){
return instance;
}
}
3、懒汉式(线程不安全)
//懒汉式(线程不安全)
class Singleton{
//静态变量
private static Singleton instance;
//构造器私有化
private Singleton(){}
//提供一个公开的静态方法,获取实例对象
public static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
优点:有懒加载效果,但是只能在单线程下使用
缺点:在多线程情况下,可能会产生多个实例
产生多个实例:在多线程下,一个线程进入 if 条件判断,还未继续执行,获取的时间片到期,切换另一个线程执行,另一个线程也通过了 if 条件判断,这时便会创建多个实例对象。
4、懒汉式(线程安全,同步方法)
//懒汉式(线程安全)
class Singleton{
//静态变量
private static Singleton instance;
//构造器私有化
private Singleton(){}
//提供一个公开的静态方法,获取实例对象
public static synchronized Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
优点:解决了线程不安全问题
缺点:获取实例对象时,需要执行同步代码,效率低
5、懒汉式(线程不安全,同步代码块)
//懒汉式(线程不安全)
class Singleton{
//静态变量
private static Singleton instance;
//构造器私有化
private Singleton(){}
//提供一个公开的静态方法,获取实例对象
public static Singleton getInstance(){
if (instance == null){
synchronized (Singleton.class){
instance = new Singleton();
}
}
return instance;
}
}
6、双重检查
//懒汉式(双重验证)
class Singleton{
//静态变量
private static Singleton instance;
//构造器私有化
private Singleton(){}
//提供一个公开的静态方法,获取实例对象
public static Singleton getInstance(){
if (instance == null){
synchronized (Singleton.class){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
优点:开发中推荐使用,线程安全且懒加载,效率较高
7、静态内部类
//静态内部类
class Singleton{
//构造器私有化
private Singleton(){}
private static class SingletonInstance{
private static final Singleton INSTANCE = new Singleton();
}
//提供一个公开的静态方法,获取实例对象
public static Singleton getInstance(){
return SingletonInstance.INSTANCE;
}
}
1、这种方式采用了类加载机制来保证初始化实例时只有一个线程。
2、静态内部类方式,在Singleton类被 类加载 时并不会立即实例化,而是需要实例化时,调用 getInstance() 方法,才会加载 SingletonInstance 类,从而完成 Singleton 的实例化。
3、类的静态属性只会在第一次加载类时初始化,所以在这里,JVM帮助我们保证了线程的安全性(类加载时是线程安全的),在类进行初始化时,别的线程是无法进入的。
优点:线程安全,利用静态内部类特点实现延迟加载,效率高。
推荐使用
8、枚举
//枚举
enum Singleton{
INSTANCE;
}
Singleton instance = Singleton.INSTANCE;
1、JDK1.5中添加枚举实现单例,线程安全,可以防止反序列化
2、Effective Java 作者推荐使用
JDK源码中的单例
/**
* java.lang.Runtime
* 部分源码
*/
public class Runtime {
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
}
简单工厂
简单工厂模式属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品的实例。
传统方式
/**
* 把 SpringBootTestApplicationDemo 这个类当作 pizzaStore
*/
public class SpringBootTestApplicationDemo {
public static void main(String[] args) {
new PizzaOrder();
}
}
/**
* 简单 demo
* 整体的需求
* 有一个披萨店 pizzaStore,披萨店里用户输入自己想要吃的 披萨,生产出对应的披萨(这里有一个披萨的订单 pizzaOrder)
* 展示披萨的整个流程: 准备原材料 ===> 烘焙 ===> 切割 ===> 打包
*
* demo的目标: 使用简单工厂进行优化
*/
abstract class Pizza{
/**
* 具体披萨的名字
*/
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
/**
* 不同的 披萨需要准备不同的原材料,写成抽象方法
* 准备原材料
*/
public abstract void prepare();
/**
* 烘焙
*/
public void bake(){
System.out.println(name + "烘焙");
}
/**
* 切割
*/
public void slice(){
System.out.println(name + "切割");
}
/**
* 打包
*/
public void box(){
System.out.println(name + "打包");
}
}
class Greece extends Pizza{
@Override
public void prepare() {
System.out.println(getName() + "准备");
}
}
class Cheese extends Pizza{
@Override
public void prepare() {
System.out.println(getName() + "准备");
}
}
/**
* 披萨订单
*/
class PizzaOrder{
private Pizza pizza;
public PizzaOrder(){
while (true){
String pizzaType = productionPizza();
if (pizzaType.equals("break")){
break;
}
//希腊披萨
if (pizzaType.equals("Greece")){
pizza = new Greece();
pizza.setName("希腊披萨");
}
//芝士披萨
if (pizzaType.equals("Cheese")){
pizza = new Cheese();
pizza.setName("芝士披萨");
}
pizza.prepare();
pizza.bake();
pizza.slice();
pizza.box();
}
}
/**
* 获取用户输入的披萨类型
*/
public String productionPizza(){
String readLine = null;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("please input pizza type:");
try {
readLine = bufferedReader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return readLine;
}
}
传统方式分析:
违反了OCP原则,即对扩展开放,对修改关闭,在新增加披萨种类的时候(新功能),尽可能不要需改源代码。
传统方式简单UML类图
简单工厂进行优化
/**
* 把 SpringBootTestApplicationDemo 这个类当作 pizzaStore
*/
public class SpringBootTestApplicationDemo {
public static void main(String[] args) {
new PizzaOrder(new SimpleFactory());
}
}
/**
* 简单 demo
* 整体的需求
* 有一个披萨店 pizzaStore,披萨店里用户输入自己想要吃的 披萨,生产出对应的披萨(这里有一个披萨的订单 pizzaOrder)
* 展示披萨的整个流程: 准备原材料 ===> 烘焙 ===> 切割 ===> 打包
*
* demo的目标: 使用简单工厂进行优化
*/
abstract class Pizza{
/**
* 具体披萨的名字
*/
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
/**
* 不同的 披萨需要准备不同的原材料,写成抽象方法
* 准备原材料
*/
public abstract void prepare();
/**
* 烘焙
*/
public void bake(){
System.out.println(name + "烘焙");
}
/**
* 切割
*/
public void slice(){
System.out.println(name + "切割");
}
/**
* 打包
*/
public void box(){
System.out.println(name + "打包");
}
}
class Greece extends Pizza{
@Override
public void prepare() {
System.out.println(getName() + "准备");
}
}
class Cheese extends Pizza{
@Override
public void prepare() {
System.out.println(getName() + "准备");
}
}
/**
* 披萨订单
*/
class PizzaOrder{
private Pizza pizza;
private SimpleFactory simpleFactory;//这里可以通过聚合或者组合的方式进行赋值
public PizzaOrder(SimpleFactory simpleFactory){
this.simpleFactory = simpleFactory;
while (true){
String pizzaType = productionPizza();
pizza = this.simpleFactory.getSpecificPizza(pizzaType);
if (pizza == null){
break;//没有此种类型的披萨
}
pizza.prepare();
pizza.bake();
pizza.slice();
pizza.box();
}
}
/**
* 获取用户输入的披萨类型
*/
public String productionPizza(){
String readLine = null;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("please input pizza type:");
try {
readLine = bufferedReader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return readLine;
}
}
class SimpleFactory{
private Pizza pizza;
public Pizza getSpecificPizza(String pizzaType){
if (pizzaType.equals("break")){
return pizza = null;
}
//希腊披萨
if (pizzaType.equals("Greece")){
pizza = new Greece();
pizza.setName("希腊披萨");
}
//芝士披萨
if (pizzaType.equals("Cheese")){
pizza = new Cheese();
pizza.setName("芝士披萨");
}
return pizza;
}
}
简单工厂分析:
使用简单工厂的目的是,将用户想要的披萨类型(创建的对象),交给工厂生产,降低订单类既创建对象,又管理用户输入的联系。
工厂方法模式
需求分析:
披萨项目有新的需求,客户在点披萨时,可以点不同口味的披萨,比如:上海辣椒披萨,上海芝士披萨等等,需要某地区某种口味的披萨
问题
使用简单工厂模式,可以根据地区创建不同的工厂类,生产不同口味的披萨,但是,随着地区的增加,需要创建很多的地区工厂类,显然简单工厂不能满足我们的新需求
解决方案
可以使用工厂方法模式进行优化
工厂方法模式介绍
工厂方法模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现
工厂方法模式:定义一个创建对象的抽象方法,由子类决定要实例化的类,工厂方法模式将对象的实例化推迟到子类。
需求demo的类说明:
具体代码:
/**
* 把 SpringBootTestApplicationDemo 这个类当作 pizzaStore
*/
public class SpringBootTestApplicationDemo {
public static void main(String[] args) {
new ItalianPizzaOrder();
}
}
/**
* 简单 demo
* 披萨项目有新的需求,客户在点披萨时,可以点不同口味的披萨,比如:上海辣椒披萨,上海芝士披萨等等,需要某地区某种口味的披萨
*
* demo的目标: 使用工厂方法进行优化
*/
abstract class Pizza{
/**
* 具体披萨的名字
*/
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
/**
* 不同的 披萨需要准备不同的原材料,写成抽象方法
* 准备原材料
*/
public abstract void prepare();
/**
* 烘焙
*/
public void bake(){
System.out.println(name + "烘焙");
}
/**
* 切割
*/
public void slice(){
System.out.println(name + "切割");
}
/**
* 打包
*/
public void box(){
System.out.println(name + "打包");
}
}
/**
* 希腊辣椒披萨
*/
class GreecePepperPizza extends Pizza{
@Override
public void prepare() {
System.out.println(getName() + "准备");
}
}
/**
* 希腊芝士披萨
*/
class GreeceCheesePizza extends Pizza{
@Override
public void prepare() {
System.out.println(getName() + "准备");
}
}
/**
* 意式辣椒披萨
*/
class ItalianPepperPizza extends Pizza{
@Override
public void prepare() {
System.out.println(getName() + "准备");
}
}
/**
* 意式芝士披萨
*/
class ItalianCheesePizza extends Pizza{
@Override
public void prepare() {
System.out.println(getName() + "准备");
}
}
/**
* 披萨订单 充当工厂的角色
*/
abstract class PizzaOrder{
private Pizza pizza;
public abstract Pizza createPizzaFactoryMethods(String pizzaType);
public PizzaOrder(){
while (true){
String pizzaType = productionPizza();
pizza = createPizzaFactoryMethods(pizzaType);
if (pizza == null){
break;//没有此种类型的披萨
}
pizza.prepare();
pizza.bake();
pizza.slice();
pizza.box();
}
}
/**
* 获取用户输入的披萨类型
*/
public String productionPizza(){
String readLine = null;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("please input pizza type:");
try {
readLine = bufferedReader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return readLine;
}
}
class GreecePizzaOrder extends PizzaOrder{
private Pizza pizza;
@Override
public Pizza createPizzaFactoryMethods(String pizzaType) {
//客户端输入break结束
if (pizzaType.equals("break")){
return pizza = null;
}
//客户端输入 greecePepper 返回 希腊辣椒披萨 对象
if (pizzaType.equals("greecePepper")){
pizza = new GreecePepperPizza();
pizza.setName("希腊辣椒披萨");
}
if (pizzaType.equals("greeceCheese")){
pizza = new GreeceCheesePizza();
pizza.setName("希腊芝士披萨");
}
return pizza;
}
}
class ItalianPizzaOrder extends PizzaOrder{
private Pizza pizza;
@Override
public Pizza createPizzaFactoryMethods(String pizzaType) {
//客户端输入break结束
if (pizzaType.equals("break")){
return pizza = null;
}
//客户端输入 italianPepper 返回 意式辣椒披萨 对象
if (pizzaType.equals("italianPepper")){
pizza = new ItalianPepperPizza();
pizza.setName("意式辣椒披萨");
}
if (pizzaType.equals("italianCheese")){
pizza = new ItalianCheesePizza();
pizza.setName("意式芝士披萨");
}
return pizza;
}
}
抽象工厂
1、抽象工厂模式:定义一个 Interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类。
2、抽象工厂模式可以将简单工厂和工厂方法模式进行整合。
3、从设计层面看,抽象工厂就是对简单工厂模式的改进(或者称为进一步的抽象)
3、将工厂抽象成两层,AbstractFactory(抽象工厂)和具体实现的工厂子类。
需求:
将工厂方法模式的披萨项目,客户在点披萨时,可以点不同口味的披萨,比如:上海辣椒披萨,上海芝士披萨等等,需要某地区某种口味的披萨,改进为抽象工厂模式
抽象工厂UML类图:
代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* 把 SpringBootTestApplicationDemo 这个类当作 pizzaStore
*/
public class SpringBootTestApplicationDemo {
public static void main(String[] args) {
new PizzaOrder(new GreecePizzaFactory());
}
}
/**
* 简单 demo
* 披萨项目有新的需求,客户在点披萨时,可以点不同口味的披萨,比如:上海辣椒披萨,上海芝士披萨等等,需要某地区某种口味的披萨
*
* demo的目标: 使用抽象工厂进行优化
*/
abstract class Pizza{
/**
* 具体披萨的名字
*/
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
/**
* 不同的 披萨需要准备不同的原材料,写成抽象方法
* 准备原材料
*/
public abstract void prepare();
/**
* 烘焙
*/
public void bake(){
System.out.println(name + "烘焙");
}
/**
* 切割
*/
public void slice(){
System.out.println(name + "切割");
}
/**
* 打包
*/
public void box(){
System.out.println(name + "打包");
}
}
/**
* 希腊辣椒披萨
*/
class GreecePepperPizza extends Pizza{
@Override
public void prepare() {
System.out.println(getName() + "准备");
}
}
/**
* 希腊芝士披萨
*/
class GreeceCheesePizza extends Pizza{
@Override
public void prepare() {
System.out.println(getName() + "准备");
}
}
/**
* 意式辣椒披萨
*/
class ItalianPepperPizza extends Pizza{
@Override
public void prepare() {
System.out.println(getName() + "准备");
}
}
/**
* 意式芝士披萨
*/
class ItalianCheesePizza extends Pizza{
@Override
public void prepare() {
System.out.println(getName() + "准备");
}
}
/**
* 披萨订单 充当工厂的角色
*/
class PizzaOrder{
private Pizza pizza;
private AbstractFactory abstractFactory;
public PizzaOrder(AbstractFactory abstractFactory){
this.abstractFactory = abstractFactory;
while (true){
String pizzaType = productionPizza();
pizza = this.abstractFactory.createPizza(pizzaType);
if (pizza == null){
break;//没有此种类型的披萨
}
pizza.prepare();
pizza.bake();
pizza.slice();
pizza.box();
}
}
/**
* 获取用户输入的披萨类型
*/
public String productionPizza(){
String readLine = null;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("please input pizza type:");
try {
readLine = bufferedReader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return readLine;
}
}
/**
* 抽象工厂 接口
*/
interface AbstractFactory{
Pizza createPizza(String pizzaType);
}
/**
* 希腊披萨工厂
*/
class GreecePizzaFactory implements AbstractFactory{
private Pizza pizza;
@Override
public Pizza createPizza(String pizzaType) {
//客户端输入break结束
if (pizzaType.equals("break")){
return pizza = null;
}
//客户端输入 greecePepper 返回 希腊辣椒披萨 对象
if (pizzaType.equals("greecePepper")){
pizza = new GreecePepperPizza();
pizza.setName("希腊辣椒披萨");
}
if (pizzaType.equals("greeceCheese")){
pizza = new GreeceCheesePizza();
pizza.setName("希腊芝士披萨");
}
return pizza;
}
}
/**
* 意式披萨工厂
*/
class ItalianPizzaFactory implements AbstractFactory{
private Pizza pizza;
@Override
public Pizza createPizza(String pizzaType) {
//客户端输入break结束
if (pizzaType.equals("break")){
return pizza = null;
}
//客户端输入 italianPepper 返回 意式辣椒披萨 对象
if (pizzaType.equals("italianPepper")){
pizza = new ItalianPepperPizza();
pizza.setName("意式辣椒披萨");
}
if (pizzaType.equals("italianCheese")){
pizza = new ItalianCheesePizza();
pizza.setName("意式芝士披萨");
}
return pizza;
}
}
总结:
在创建的对象,需求简单时,可以使用简单工厂。
在面对详细有分类的需求时,可以使用抽象工厂。
工厂模式的意义:将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的以来关系解耦。提高项目的扩展和维护性。
JDK源码中的简单工厂
原型模式
展示一个小需求,引出原型模式
需求:克隆羊问题
现有一只羊,名字为tom,年龄为10岁,颜色:白色
需要创建具有相同属性的十只羊
传统方式代码:
public class SpringBootTestApplicationDemo {
public static void main(String[] args) {
Sheep sheep1 = new Sheep("tom", 10, "白色");
Sheep sheep2 = new Sheep("tom", 10, "白色");
Sheep sheep3 = new Sheep("tom", 10, "白色");
Sheep sheep4 = new Sheep("tom", 10, "白色");
Sheep sheep5 = new Sheep("tom", 10, "白色");
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Sheep{
private String name;
private Integer age;
private String color;
}
优点:简单
缺点:总需要初始化对象,而不是动态的获得对象运行时的状态,不够灵活
改进方式:
Java Object类中 clone() 方法,可以复制对象,但是需要实现 Cloneable 接口,该接口具有复制对象的能力 ===> 原型模式
原型模式
1、概述:原型模式是指,用原型实例创建对象的种类,并通过拷贝这些原型,创建新的对象。
2、原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无序知道如何创建的细节
3、工作原理:通过将一个对象原型传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即:对象.clone()
原型模式是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而不是通过实例化类来创建。原型模式涉及一个原型对象,该对象是要被复制的对象,以及一个客户端对象,该对象负责复制原型对象。
原型模式的核心思想是通过复制已有对象的属性来创建新的对象,这种复制可以是浅复制(shallow copy)或深复制(deep copy)
浅复制:只复制对象的基本属性,而不复制对象内部引用类型的属性。新对象和原对象共享相同的引用类型属性。
深复制:不仅复制对象的基本属性,还递归复制对象内部所有引用类型的属性。新对象和原对象各自拥有独立的引用类型属性
代码:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 原型模式改进
*/
public class SpringBootTestApplicationDemo {
public static void main(String[] args) {
Sheep sheep1 = new Sheep("tom", 10, "白色");
Sheep sheep2 = (Sheep) sheep1.clone();
Sheep sheep3 = (Sheep) sheep1.clone();
Sheep sheep4 = (Sheep) sheep1.clone();
Sheep sheep5 = (Sheep) sheep1.clone();
System.out.println("sheep2 ===>" + sheep2);
System.out.println("sheep3 ===>" + sheep3);
System.out.println("sheep4 ===>" + sheep4);
/**
* 执行结果
* sheep2 ===>Sheep(name=tom, age=10, color=白色)
* sheep3 ===>Sheep(name=tom, age=10, color=白色)
* sheep4 ===>Sheep(name=tom, age=10, color=白色)
*/
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Sheep implements Cloneable{
private String name;
private Integer age;
private String color;
@Override
protected Object clone() {
Sheep sheep = null;
try {
sheep = (Sheep) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return sheep;
}
}
使用原型模式之后,如 Sheep 增加其它属性后,不影响最后拷贝的对象。
持续更新中....