个人博客:haichenyi.com。感谢关注
设计模式的分类
- 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
- 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
- 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
我只讲我用的多的,用的多的印象深刻,知道怎么讲,用的少的,不知道怎么讲。只讲我熟练的。
一、单例模式
单例模式,我想应该做过开发的人都用过。
懒汉式(用的时候初始化,延迟加载)
public class MySocket{
private static MySocket instance;
private MySocket(){}
public static synchronized MySocket getInstance(){
if(null == instance){
instance = new MySocket();
}
return instance;
}
}
这里在懒汉式的单例模式中加上了同步锁synchronized,所以,这是线程安全的,但是,也是因为锁,所以造成的效率低,可以根据不同实际情况判断是否需要加同步锁。
饿汉式(加载类的时候直接初始化)
public class MySocket{
private static MySocket instance = new MySocket();
private MySocket(){}
public static MySocket getInstance(){
return instance;
}
}
双重校验锁
public class MySocket{
private static MySocket instance;
private MySocket(){}
public static MySocket getInstance(){
if(null == instance){
synchronized(MySocket.class){
if(null == instance){
instance = new MySocket();
}
}
}
return instance;
}
}
这里的双重校验锁,其实就是我这里的线程安全懒汉式的升级版本,双重校验锁很多开源框架都是用的这种单例,比方说:EventBus。关于单例模式的其他变种我就不说了。单例模式的最终目的,就是全局单例,一个项目不论哪里调用这个类都是引用的同一个对象。
二、工厂模式
/**
* Author: 海晨忆.
* Date: 2017/12/21
* Desc:
*/
public class FragmentFactory {
public static BaseFragment createFragment(Class extends BaseFragment> clz) {
return createFragment(clz, null);
}
public static BaseFragment createFragment(Class extends BaseFragment> clz, Bundle bundle) {
if (HomeFragment.class == clz) {
return new HomeFragment();
} else if (MyClothesFragment.class == clz) {
return new MyClothesFragment();
} else if (WardrobeStructureFragment.class == clz) {
return new WardrobeStructureFragment();
} else if (WifiFragment.class == clz) {
return new WifiFragment();
} else if (WardrobeConfigFragment.class == clz) {
return new WardrobeConfigFragment();
} else if (ShowFragment.class == clz) {
return new ShowFragment();
} else {
throw new NullPointerException("not found fragment");
}
}
public static T createDialogFragment(Class clz) {
return createDialogFragment(clz, null);
}
@SuppressWarnings("unchecked")
private static T createDialogFragment(Class clz, Bundle bundle) {
if (clz == IconDialogFragment.class) {
return (T) new IconDialogFragment();
} else if (clz == PasswordDialogFragment.class) {
return (T) PasswordDialogFragment.newInstance();
} else {
throw new NullPointerException("not found fragment");
}
}
}
这个fragment工厂类,就是我项目里面用到的。常用的工厂模式就是静态工厂,利用static方法,我这里的工厂就是静态工厂。我们常说的工厂方法对应的这里是什么呢?其实,工厂方法也是一个普通的方法,对应的这里就是createFragment(Class extends BaseFragment> clz)。工厂模式什么时候用呢?在需要大量类似的数据的时候(个人观点),Android里面,工厂方法用的最多的就是创建Fragment。
三、抽象工厂模式
public interface IFragmentFactory{
BaseFragment createFragment();
}
public class HomeFactory implements IFragmentFactory{
@Override
public BaseFragment createFragment(){
return new HomeFragment();
}
}
public class WifiFragment implements IFragmentFactory{
@Override
public BaseFragment createFragment(){
return new WifiFragment();
}
}
我把上面的静态工厂类,改成了抽象工厂类,就是上面的代码。就是有一个工厂接口或者抽象的工厂类,然后创建不同的工厂类去实现这个接口,实现对应的类,返回你需要的东西
四、建造者模式
我之前写Luban源码解析的时候就讲过建造者模式,可以去看一下,就在源码解析的一开始
package com.haichenyi.mytakephoto;
/**
* Author: 海晨忆
* Date: 2018/3/6
* Desc:
*/
public class DataBean {
private String name;
private int age;
private String sex;
public DataBean(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.sex = builder.sex;
}
public static class Builder {
private String name;
private int age = 20;
private String sex = "男";
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setAge(int age) {
this.age = age;
return this;
}
public Builder setSex(String sex) {
this.sex = sex;
return this;
}
public DataBean build() {
return new DataBean(this);
}
}
}
上面的代码就是一个DataBean类,用建造者模式创建。要是还是不懂,你可以理解成,我们常常在写bean类的时候,往往要写set方法,你可以理解成,把set方法写在Builder里面,在Builder里面赋好值之后,在我们bean类的构造方法里面传递过来就可以了。
五、原型模式
这个模式我之前没有用到过,研究了一下,就是一个clone()方法,我个人觉得,我项目中要是用,也是在从服务器拿到一个list数据,循环解析的时候肯定要new很多个对象,这个时候,我在for循环外面new一个对象,之后,在for循环里面去拷贝,重新赋值,就不用每次new一个新对象,new新对象是耗性能的,clone是本地方法,直接操作二进制流,性能会好很多。
再就是这个克隆方法,也就是拷贝,分深拷贝和浅拷贝
- 浅拷贝:只会复制8基本数据类型:boolean,short,float,double,int,long,char,byte。引用类型不会被拷贝(PS:String属于引用类型,但是它属于浅拷贝)
- 深拷贝:基本数据类型和引用类型都会被拷贝
浅拷贝
package com.haichenyi.mytakephoto;
import java.util.ArrayList;
/**
* Author: 海晨忆
* Date: 2018/3/7
* Desc:
*/
public class Person implements Cloneable {
private String name;
private int age;
private ArrayList hobby;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public ArrayList getHobby() {
return hobby;
}
@Override
protected Person clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
person.hobby = (ArrayList) this.hobby.clone();
return person;
}
}
上面就是一个浅拷贝的例子,实现Cloneable接口,重写clone()方法,前面说了只能拷贝8中数据类型,为什么这里有一个ArrayList容器呢?因为,java里面很多容器他自己就实现了Cloneable接口,所以,就能被拷贝。
深拷贝
public class Prototype implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private String string;
private SerializableObject obj;
/* 浅拷贝 */
public Object clone() throws CloneNotSupportedException {
Prototype proto = (Prototype) super.clone();
return proto;
}
/* 深拷贝 */
public Object deepClone() throws IOException, ClassNotFoundException {
/* 写入当前对象的二进制流 */
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
/* 读出二进制流产生的新对象 */
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
public SerializableObject getObj() {
return obj;
}
public void setObj(SerializableObject obj) {
this.obj = obj;
}
}
class SerializableObject implements Serializable {
private static final long serialVersionUID = 1L;
}
上面就是一个深拷贝的例子,就是走的二进制流。
我们在写项目的时候,哪会去考虑深拷贝,浅拷贝,我们关心的是只要能把我需要的东西拷贝过去就行了。所以,我们只要把我们自己的类实现Cloneable接口并且实现clone方法,并且,把这个类里面的引用类型也实现Cloneable接口并且实现clone方法即可
package com.haichenyi.mytakephoto;
import java.util.ArrayList;
/**
* Author: 海晨忆
* Date: 2018/3/7
* Desc:
*/
public class Person implements Cloneable {
private String name;
private int age;
private ArrayList hobby;
private Birthday birthday;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setHobby(ArrayList hobby) {
this.hobby = hobby;
}
public void setBirthday(Birthday birthday) {
this.birthday = birthday;
}
@Override
protected Person clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
person.hobby = (ArrayList) this.hobby.clone();
person.birthday = this.birthday.clone();
return person;
}
}
package com.haichenyi.mytakephoto;
/**
* Author: 海晨忆
* Date: 2018/3/6
* Desc:
*/
public class Birthday implements Cloneable{
private int year;
private int month;
private int day;
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
@Override
protected Birthday clone() throws CloneNotSupportedException {
Birthday birthday = (Birthday) super.clone();
return birthday;
}
}
就像上面这样写就可以了,我们的Person类里面有一个Birthday引用类,我们的这个引用类实现Cloneable接口和clone()方法
PS:原型模式不会走构造方法,所以,构造方法里面的代码不会被执行