Java实现23种设计模式教程(1)
个人简介
作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门。
@[toc]
Java设计模式
单例模式
单例模式步骤:
1.构造器私有
2.创建对象(比如饿汉式就是先new,懒汉式就是判断为null再new)
3.返回实例对象(都是一样)
饿汉式
所谓的饿汉式,也就是提前new好对象,再提供一个方法,返回这个new好的对象实例。还有要把构造器私有化,通过方法new对象,控制到只有一个实例对象
饿汉式缺点:虽然是线程安全,但是会浪费资源,因为我们的饿汉式是一开始就new对象,如果没有人使用到这个对象,那就是一种资源的浪费,所以下面我们要讲懒汉式,懒汉式线程不安全,但是不会造成资源浪费,因为只有用到了才会new对象
代码实现:
1:实体类只需要正常写:
public class person {
private String id;
private String name;
private int age;
public person() {
}
public person(String id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
2:单例类:
public class hungry {
/**
* 单例模式-饿汉式
*/
//1.创建static final对象
private static final person person=new person();
//2.构造器私有,为了让人只能用类去调用getInstance方法获取实例,而不能new这个单例的对象
private hungry(){
}
//3.返回对象
public static person getInstance(){
return person;
}
}
3.测试:
public static void main(String[] args) {
//测试单例
person p1 = hungry.getInstance();
person p2 = hungry.getInstance();
//hashcode相同证明是同一个对象
System.out.println("p1.hashCode:"+p1.hashCode());
System.out.println("p2.hashCode:"+p2.hashCode());
System.out.println("p1==p2:"+(p1==p2));
}
4.结果:
p1.hashCode:1690716179
p2.hashCode:1690716179
p1==p2:true
饿汉式在JDK中的Runtime类运用
查看Runtime源码:
public class Runtime {
private static final Runtime currentRuntime = new Runtime();
private static Version version;
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class {@code Runtime} are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the {@code Runtime} object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
这就是一种标准的单例模式-饿汉式
懒汉式(不加锁,不安全)
懒汉式是线程不安全的,但是他具有懒加载机制,也就是用到才new对象,这样不会造成资源的浪费
public class lazyNotSync {
/**
* 单例模式-懒汉式(不加锁) 线程不安全
*/
//1.首先,单例模式要把构造器私有
private lazyNotSync(){
}
//2.懒汉式的对象置为null
private static person person=null;
//3.返回实例
public static person getInstance(){
if(person==null){
person=new person(); //这个new对象并赋值不是原子操作,所以在多线程是不安全的
return person;
}else {
return person;
}
}
}
测试懒汉式不加锁的线程不安全性
class lazyNotSyncMain{
public static void main(String[] args) throws InterruptedException {
//这里不能用ArrayList,因为ArrayList是线程不安全的,所以在多线程的add,会导致少添加的情况
CopyOnWriteArrayList<Object> list = new CopyOnWriteArrayList<>();
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
list.add(lazyNotSync.getInstance());
}
}).start();
}
Thread.sleep(100);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).hashCode());
}
}
}
结果hashcode不一致,说明不是一个对象:
1929600551
1690716179
1053782781
1211888640
564160838
懒汉式(加锁,安全)
public class lazySync {
/**
* 单例模式-懒汉式,加锁,保证线程安全,但是呢,加了锁之后性能会下降
*
*/
//1.构造器私有
private lazySync(){
}
//2.创建对象
private static person person=null;
private static final Object lock=new Object();
//3.返回实例
public static person getInstance(){
synchronized (lock){
if(person==null){
person=new person();
return person;
} else {
return person;
}
}
}
}
测试安全性
class lazySyncMain{
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
System.out.println(lazySync.getInstance().hashCode());
}).start();
}
}
}
结果:
1226907195
1226907195
1226907195
1226907195
1226907195
1226907195
1226907195
1226907195
1226907195
1226907195
利用静态内部类
public class staticClass {
/**
* 利用静态内部类的特性来实现单例模式(推荐)
* 优点:线程安全,懒加载(节省资源)
* 可以说是饿汉式和懒汉式更好的一种
* =====
* 写法类似于饿汉式。。只是把new对象放到一个私有的静态内部类中
*
* =====
* 静态内部类的特性:
* 当classloader时静态内部类不会随着加载,当我们去调用时才会加载(懒加载)
*/
//1.构造器私有
private staticClass(){
}
//如果这段代码不放到静态内部类中,它将随着类加载而new对象(占资源)
// private static final person person=new person();
//2.创建对象(只不过是在静态内部类中创建对象)
private static class personStatic{
private static final person person=new person();
}
//3.返回对象
public static person getInstance(){
return personStatic.person;
}
}
测试:
class staticClassMain{
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(staticClass.getInstance().hashCode());
}
}).start();
}
}
}
利用枚举(不太懂)
原型模式(多例)
原型模式其实就是复制的意思,包含着深拷贝和浅拷贝。浅拷贝复制的引用数据类型变量只是地址,深拷贝则是内容
实现原型模式的实体类要实现Cloneable接口
注意:实现了Cloneable的类才能拷贝(克隆)
浅拷贝
public class person implements Cloneable {
private String id;
private String name;
private int age;
private Firend firend; //朋友 ---模拟深拷贝和浅拷贝
public person() {
}
public person(String id, String name, int age, Firend firend) {
this.id = id;
this.name = name;
this.age = age;
this.firend = firend;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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 Firend getFirend() {
return firend;
}
public void setFirend(Firend firend) {
this.firend = firend;
}
@Override
public String toString() {
return "person{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", firend=" + firend +
'}';
}
//浅拷贝
@Override
protected person clone() throws CloneNotSupportedException {
person person = (person) super.clone(); //克隆对象
return person;
}
}
public class Firend {
private String id;
private String name;
public Firend() {
}
public Firend(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Firend{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
public class prototypeMain {
public static void main(String[] args) throws CloneNotSupportedException {
person person = new person("001","张三",18,new Firend("999","小明同学"));
person p1 = person.clone();
System.out.println("person是否=p1:"+(person==p1)); //false ,说明克隆出来的对象不是同一个对象
System.out.println("person:"+person);
System.out.println("p1:"+p1);
//说明我们的firend是浅拷贝
System.out.println("person.getFirend().hashCode()==p1.getFirend().hashCode():"+(person.getFirend().hashCode()==p1.getFirend().hashCode()));
}
结果:
person是否=p1:false
person:person{id='001', name='张三', age=18, firend=Firend{id='999', name='小明同学'}}
p1:person{id='001', name='张三', age=18, firend=Firend{id='999', name='小明同学'}}
person.getFirend().hashCode()==p1.getFirend().hashCode():true
深拷贝
深拷贝有多种方法,这里我们只使用一种,也是最简单的一种
person和Firend都要实现Cloneable和重写clone方法。。。。。。。。。。。。。才能实现深拷贝
public class person implements Cloneable {
private String id;
private String name;
private int age;
private Firend firend; //朋友 ---模拟深拷贝和浅拷贝
public person() {
}
public person(String id, String name, int age, Firend firend) {
this.id = id;
this.name = name;
this.age = age;
this.firend = firend;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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 Firend getFirend() {
return firend;
}
public void setFirend(Firend firend) {
this.firend = firend;
}
@Override
public String toString() {
return "person{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", firend=" + firend +
'}';
}
//深拷贝
@Override
protected person clone() throws CloneNotSupportedException {
person person = (person) super.clone(); //克隆对象
//Firend也要实现Cloneable和clone方法
//深拷贝:把引用数据类型变量单独的克隆并复制到person.firend
person.firend=firend.clone();
return person;
}
}
public class Firend implements Cloneable {
private String id;
private String name;
public Firend() {
}
public Firend(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Firend clone() throws CloneNotSupportedException {
Firend firend = (Firend) super.clone();
return firend;
}
@Override
public String toString() {
return "Firend{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
public class prototypeMain {
public static void main(String[] args) throws CloneNotSupportedException {
person person = new person("001","张三",18,new Firend("999","小明同学"));
person p1 = person.clone();
System.out.println("person是否=p1:"+(person==p1)); //false ,说明克隆出来的对象不是同一个对象
System.out.println("person:"+person);
System.out.println("p1:"+p1);
//说明我们的firend是深拷贝
System.out.println("person.getFirend().hashCode()==p1.getFirend().hashCode():"+(person.getFirend().hashCode()==p1.getFirend().hashCode()));
}
}
结果:
person是否=p1:false
person:person{id='001', name='张三', age=18, firend=Firend{id='999', name='小明同学'}}
p1:person{id='001', name='张三', age=18, firend=Firend{id='999', name='小明同学'}}
person.getFirend().hashCode()==p1.getFirend().hashCode():false
工厂模式
工厂模式分为简单工厂和工厂方法,工厂模式和抽象工厂模式不是一个概念
总结:工厂模式只是生产同一类产品(比如手机工厂生产手机对象,电脑工厂生产电脑对象)
- 点赞
- 收藏
- 关注作者
评论(0)