创建模式
原型模式prototype:
简介:用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。
切入点:课表排课:常规计算42个变量
弊端:代码量大,不利于维护
解决办法:设计两个变量Json.parse(json.stringfy(变量))
概念:将原型对象拷贝出新的实例,浅拷贝:只拷贝原型本身,不拷贝原型对象中的应用对象(堆内存)。深拷贝:会拷贝原型对象以及引用对象。
- 使用前
```
package com.javaxl.design.prototype.before;
public class Sheep {
private String name;
private String sex;
public Sheep(String name, String sex) {
this.name = name;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
package com.javaxl.design.prototype.before;
/**
*
* 将一只名字为杰克、性别为母的绵羊克隆10份;
* 要求每只绵羊的属性、性别都一致;
*
* 弊端:无法将当前的状态进行复制
*/
public class Client {
public static void main(String[] args) {
Sheep sheep1 = new Sheep("杰西", "母");
Sheep sheep2 = new Sheep("杰西", "母");
Sheep sheep3 = new Sheep("杰西", "母");
Sheep sheep4 = new Sheep("杰西", "母");
Sheep sheep5 = new Sheep("杰西", "母");
Sheep sheep6 = new Sheep("杰西", "母");
Sheep sheep7 = new Sheep("杰西", "母");
Sheep sheep8 = new Sheep("杰西", "母");
Sheep sheep9 = new Sheep("杰西", "母");
Sheep sheep10 = new Sheep("杰西", "母");
// 此时我要一只名为杰瑞的绵羊,其它绵羊属性与杰西一致;
// 那么按照这种设计,只能这么创建所需的绵羊
// 这种方式创建,目前只有两个属性问题不大,如果绵羊类有十几二十甚至更多的属性,那么是非常不方便的
Sheep sheep11 = new Sheep("杰瑞", "母");
}
}
- 使用后
```
package com.javaxl.design.prototype.after;
/**
* 使用原型设计模式进行设计
*/
public class Sheep implements Cloneable{
private String name;
private String sex;
public Sheep(String name, String sex) {
this.name = name;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
System.out.println("被克隆了...");
return obj;
}
}
package com.javaxl.design.prototype.after;
/**
* 将一只名字为杰克、性别为母的绵羊克隆10份;
* 要求每只绵羊的属性、性别都一致;
*
* 使用原型设计模式进行设计后的测试
*/
public class Client {
public static void main(String[] args) throws Exception{
Sheep sheep1 = new Sheep("杰西", "母");
Sheep sheep2 = (Sheep) sheep1.clone();
Sheep sheep3 = (Sheep) sheep1.clone();
Sheep sheep4 = (Sheep) sheep1.clone();
Sheep sheep5 = (Sheep) sheep1.clone();
Sheep sheep6 = (Sheep) sheep1.clone();
Sheep sheep7 = (Sheep) sheep1.clone();
Sheep sheep8 = (Sheep) sheep1.clone();
Sheep sheep9 = (Sheep) sheep1.clone();
Sheep sheep10 = (Sheep) sheep1.clone();
System.out.println(sheep1);
System.out.println(sheep2);
// 此时我要一只名为杰瑞的绵羊,其它绵羊属性与杰西一致;
// 按照原型设计模式,调用方Client类无需查找杰西相同部分的属性,只需变动差异部分属性进行克隆即可;
// 这种设计,目前只有两个属性使用起来感觉没多大区别,如果绵羊类有十几二十甚至更多的属性,那么感觉非常明显
sheep1.setName("杰瑞");//其它的属性不需要去关注
Sheep sheep11 = (Sheep) sheep1.clone();
System.out.println(sheep11);
}
}
浅拷贝:
package com.javaxl.design.prototype.light;
/**
* 使用原型设计模式进行设计
*/
public class Sheep implements Cloneable{
private String name;
private String sex;
private Sheep friend;
public Sheep(String name, String sex) {
this.name = name;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Sheep getFriend() {
return friend;
}
public void setFriend(Sheep friend) {
this.friend = friend;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", friend=" + friend +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
System.out.println("被克隆了...");
return obj;
}
}
```
深拷贝:
- 方式一
```
package com.javaxl.design.prototype.deep.one;
/**
* 使用原型设计模式进行设计
*/
public class Sheep implements Cloneable {
private String name;
private String sex;
private Sheep friend;
private Sheep boyFriend;
public Sheep(String name, String sex) {
this.name = name;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Sheep getFriend() {
return friend;
}
public void setFriend(Sheep friend) {
this.friend = friend;
}
public Sheep getBoyFriend() {
return boyFriend;
}
public void setBoyFriend(Sheep boyFriend) {
this.boyFriend = boyFriend;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", friend=" + friend +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
if (obj == null) {
return obj;
} else {
// 被克隆出来的绵羊(目前这只绵羊的朋友还是本体的朋友)
Sheep sheep = (Sheep) obj;
// 将本体的朋友也克隆一份出来,给克隆羊
Sheep friend = this.getFriend();
if (friend !=null){
sheep.setFriend((Sheep) friend.clone());
}
return sheep;
}
}
}
package com.javaxl.design.prototype.deep.one;
/**
* 将一只名字为杰克、性别为母的绵羊克隆10份;
* 要求每只绵羊的属性、性别都一致;
* <p>
* 使用原型设计模式进行设计后的测试
*/
public class Client {
public static void main(String[] args) throws Exception {
Sheep sheep1 = new Sheep("杰西", "母");
Sheep friend_jiexi = new Sheep("杰西的朋友", "公");
Sheep boyFriend_jiexi = new Sheep("杰西的男朋友", "公");
sheep1.setFriend(friend_jiexi);
sheep1.setBoyFriend(boyFriend_jiexi);
Sheep sheep2 = (Sheep) sheep1.clone();
System.out.println("第1只叫杰西的绵羊的朋友:" + sheep1.getFriend().hashCode());
System.out.println("第2只叫杰西的绵羊的朋友:" + sheep2.getFriend().hashCode());
System.out.println("第1只叫杰西的绵羊的男朋友:" + sheep1.getBoyFriend().hashCode());
System.out.println("第2只叫杰西的绵羊的男朋友:" + sheep2.getBoyFriend().hashCode());
}
}
```
![](创建型模式.assets/1582343860268-1582641669694.png)
- 方式二
```
package com.javaxl.design.prototype.deep.two;
import java.io.*;
/**
* 使用原型设计模式进行设计
*/
public class Sheep implements Cloneable,Serializable{
private String name;
private String sex;
private Sheep friend;
private Sheep boyFriend;
public Sheep getBoyFriend() {
return boyFriend;
}
public void setBoyFriend(Sheep boyFriend) {
this.boyFriend = boyFriend;
}
public Sheep(String name, String sex) {
this.name = name;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Sheep getFriend() {
return friend;
}
public void setFriend(Sheep friend) {
this.friend = friend;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", friend=" + friend +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
System.out.println("被克隆了...");
return obj;
}
protected Object deepClone() throws CloneNotSupportedException, IOException, ClassNotFoundException {
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// 获取对象输出流
ObjectOutputStream oos = new ObjectOutputStream(bos);
// 将当前的对象
oos.writeObject(this);
// 反序列化
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
Object obj = ois.readObject();
return obj;
}
}
public class Client {
public static void main(String[] args) throws Exception {
Sheep sheep1 = new Sheep("杰西", "母");
Sheep friend_jiexi = new Sheep("杰西的朋友", "公");
Sheep boyFriend_jiexi = new Sheep("杰西的男朋友", "公");
sheep1.setFriend(friend_jiexi);
sheep1.setBoyFriend(boyFriend_jiexi);
Sheep sheep2 = (Sheep) sheep1.deepClone();
System.out.println("第1只叫杰西的绵羊的朋友:" + sheep1.getFriend().hashCode());
System.out.println("第2只叫杰西的绵羊的朋友:" + sheep2.getFriend().hashCode());
System.out.println("第1只叫杰西的绵羊的男朋友:" + sheep1.getBoyFriend().hashCode());
System.out.println("第2只叫杰西的绵羊的男朋友:" + sheep2.getBoyFriend().hashCode());
}
}
```
注意事项和细节
- 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
- 不用重新初始化对象,而是动态地获得对象运行时的状态
- 如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码
缺点:
1、需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了 ocp 原则
2、实现深克隆的时候可能需要比较复杂的代码
结论:从对象创建的角度上来说,原型模式设计让相似的类实例创建更加的便捷
单例模式singlon:
简介:保证一个类只有一个实例,并提供一个访问它的全局访问点
切入点:Spring中bean对象是单例的?
优点:极大的节约了Jvm的内存空间
缺点:会存在变量污染问题;
public class Demo1 {
// public static void main(String[] args) {
// HashMap hm1 = new HashMap();
// hm1.put("name","zs");
// hm1.put("sex","女");
// HashMap hm2 = hm1;
// hm1.put("age","18");
// hm2.put("like","男");
// System.out.println(hm1);
// System.out.println(hm2);
// }
public static void main(String[] args) {
HashMap hm1 = new HashMap();
hm1.put("name","zs");
hm1.put("sex","女");
HashMap hm2 = (HashMap) hm1.clone();
hm1.put("age","18");
hm2.put("like","男");
System.out.println(hm1);
System.out.println(hm2);
}
}
综上:Spring就是提供多例配置socpe="prototype"
体现形式:
- 饿汉式(静态常量) final static Dbaccess dbaccess=new Dbaccess();
- 饿汉式(静态代码块)static{}
- 懒汉式(线程不安全) if()
- 懒汉式(线程安全,同步代码块) synchronized
- 懒汉式(线程安全,同步方法)
- 双重检查
- 静态内部类
- 枚举
/** * 饿汉式(静态常量) */ public class DBAccess { // 构造器私有化,避免外部创建对象 private DBAccess() { } // static修饰,保障其能够被静态方法访问 private final static DBAccess dbAccess = new DBAccess(); // 外部直接调用静态方法实例化对象 public static DBAccess getInstance() { return dbAccess; } } /** * 饿汉式(静态代码块) */ class DBAccess2 { private DBAccess2() { } private static DBAccess2 dbAccess = null; static { dbAccess = new DBAccess2(); } public static DBAccess2 getInstance() { return dbAccess; } } /** * 懒汉式(线程不安全) */ class DBAccess3 { private DBAccess3() { } private static DBAccess3 dbAccess = null; public static DBAccess3 getInstance() { if (dbAccess == null) { dbAccess = new DBAccess3(); } return dbAccess; } } /** * 懒汉式(同步代码块) */ class DBAccess4 { private DBAccess4() { } private static DBAccess4 dbAccess = null; public static DBAccess4 getInstance() { synchronized (DBAccess4.class) { if (dbAccess == null) { dbAccess = new DBAccess4(); } } return dbAccess; } } /** * 懒汉式(线程安全,同步方法) */ class DBAccess5 { private DBAccess5() { } private static DBAccess5 dbAccess = null; public synchronized static DBAccess5 getInstance() { if (dbAccess == null) { dbAccess = new DBAccess5(); } return dbAccess; } } /** * 双重检查 */ class DBAccess6 { private DBAccess6() { } private static DBAccess6 dbAccess = null; public static DBAccess6 getInstance() { if (dbAccess == null) { synchronized (DBAccess6.class) { if (dbAccess == null) { dbAccess = new DBAccess6(); } } } return dbAccess; // return new DBAccess6(); } } /** * 静态内部类 */ class DBAccess7 { private DBAccess7() { } private static class DBAccess7Instance{ private static DBAccess7 dbAccess = new DBAccess7(); } public static DBAccess7 getInstance() { return DBAccess7Instance.dbAccess; } } /** * 枚举 */ enum DBAccess8{ DBACCESS; public static DBAccess8 getInstance() { return DBAccess8.DBACCESS; } } /** * 结论: * * 单例中两种饿汉式可用,但是存在性能问题 * * 单例中三种懒汉式不推荐,存在线程安全问题,同步方法的方式解决了线程的问题,但是性能极差 * * 最后三种单例模式值得推荐 * * * *注意事项 * 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象 * 使用单例模式可以提高系统性能 * * 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用 new */
应用:
/** * Spring单例多例模式的演示、区别及选择 * * @author Administrator * */ public class Demo1 { // scope="singleton" 默认的 @Test public void test1() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml"); ParamAction p1 = (ParamAction) applicationContext.getBean("paramAction"); ParamAction p2 = (ParamAction) applicationContext.getBean("paramAction"); System.out.println(p1 == p2); } // scope="prototype" @Test public void test2() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml"); ParamAction p1 = (ParamAction) applicationContext.getBean("paramAction"); ParamAction p2 = (ParamAction) applicationContext.getBean("paramAction"); System.out.println(p1 == p2); } // 区别:单例多例的选择? @Test public void test3() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml"); ParamAction p1 = (ParamAction) applicationContext.getBean("paramAction"); ParamAction p2 = (ParamAction) applicationContext.getBean("paramAction"); p1.execute(); p2.execute(); } }
工厂模式(Factory)
简介:是用工厂方法代替new操作的一种模式。著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。
切入点:Spring中的javabean是什么时候初始化的,是容器初始化时候还是工厂创建对象初始化;
Bean生命周期:
/**
* Bean的生命周期
单例对象
出生:当容器创建时对象出生
活着:只要容器还在,对象一直活着
死亡:容器销毁,对象消亡
总结:单例对象的生命周期和容器相同
多例对象
出生:当我们使用对象时Spring框架为我们创建
活着:对象只要是在使用过程中就一直活着
死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收
*
* @author Administrator
*
*/
public class Demo2 {
// 单例对象与多例对象的初始化时间不一样 通过scope属性来演示
@Test
public void test1() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
}
// 单例对象与多例对象的初始化时间不一样 通过scope属性来演示
@Test
public void test2() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
InstanceFactory i1 = (InstanceFactory) applicationContext.getBean("instanceFactory");
i1.service();
// scope="prototype",容器关闭不会自动销毁bean对象
applicationContext.close();
}
/**
* 说明了两点:
* scope的值对应的是两个工厂类,生产javabean的模式一样;
* 1.一个是单例一个是多例
* 2.一个是立即初始化,一个是使用初始化
* 反正要初始化一次,干脆把所有的初始化操作放到监听器里面去,提高系统应用的性能
* 多例本身会耗性能,那么就尽可能在使用的时候再去创造对象
*/
@Test
public void test3() {
// ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
Resource resource = new ClassPathResource("/spring-context.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource );
InstanceFactory i1 = (InstanceFactory) beanFactory.getBean("instanceFactory");
}
}
//其他
package com.zking.single.demo;
public class InstanceFactory {
public void init() {
System.out.println("初始化方法");
}
public void destroy() {
System.out.println("销毁方法");
}
public void service() {
System.out.println("业务方法");
}
}
<bean id="instanceFactory" class="com.zking.single.demo.InstanceFactory"
scope="prototype" init-method="init" destroy-method="destroy"></bean>
//应用:将初始化放到工厂类,优化代码
public class PizzaFactory {
public static Pizza createPizza(int no){
Pizza pizza = null;
switch (no){
case 1:
pizza = new ChinesePizza();
break;
case 2:
pizza = new AmericaPizza();
break;
case 3:
pizza = new JapanPizza();
break;
}
if (pizza == null){
System.out.println("没有此披萨订购服务");
}else {
pizza.pre();
pizza.bake();
pizza.cut();
pizza.box();
}
return pizza;
}
}