以下内容根据以下网址及相关视频整理:Android设计模式之单例模式_谬谬清不给我取名字的博客-CSDN博客_android 单例模式
Android设计模式--单例模式的六种实现和单例模式讲解Volatile与Synchronized相关的并发_龙腾腾的博客-CSDN博客_android 单例 volatile
java 设计模式实战,装饰者模式之不用改变也能变强 - 掘金
目录
一、单例模式:
(1)构造方法使用private修饰,避免外部通过new创建对象;
(2)通过一个静态方法或者枚举返回单例类对象;
(3)考虑对象创建时的线程安全问题,确保单例类的对象有且仅有一个,尤其是在多线程环境下;
(4)确保单例类对象在反序列化时不会重新构建对象;
1、饿汉式单例模式:
(1)类加载时就初始化,浪费内存,不能延迟加载;
(2)基于 classloader 机制避免了多线程的同步问题,线程安全;
(3)没有加锁,调用效率高;
public class Singleton {
private static Singleton sInstance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return sInstance;
}
}
2、懒汉式单例模式:
(1)可以延迟加载;
(2)加synchronized是线程安全的,不加就是线程不安全的;
(3)加synchronized会导致调用效率很低;
不足之处:在多线程并发下这样的实现是无法保证实例是唯一的。
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
优化:懒汉线程安全模式
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
}
//方法一:添加 synchronized 关键字
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
//方法二:同步代码块实现
public static LazySingleton getInstance2() {
synchronized (LazySingleton.class) {
if (instance == null) {
instance = new LazySingleton();
}
}
return instance;
}
}
缺点:性能方面不足
3、双重检索(Double Check Lock,DCL)
(1)可以延迟加载;
(2)线程安全的;
(3)对JDK的版本有要求(1.5及以上)(需要使用volatile关键字来禁止指令重排的操作,这个在JDK1.5之后才出现)
public class Singleton {
private volatile static Singleton instance; //volatile具备 “有序性” 和 “可见性” 的特性。 第一层锁:保证变量可见性
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {//第一次判空:无需每次都加锁,提高性能
synchronized (Singleton.class) {//第二层锁:保证线程同步
if (instance == null) {//第二次判空:避免多线程同时执行getInstance()产生多个single对象
instance = new Singleton();
}
}
}
return instance;
}
}
1)、构造函数得私有,禁止其他对象直接创建实例;
2)、对外提供一个静态方法,可以获取唯一的实例;
3)、即然是双重检查模式,就意味着创建实例过程会有两层检查。第一层就是最外层的判空语句:第一处if (singleton == null),该判断没有加锁处理,避免第一次检查singleton对象非null时,多线程加锁和初始化操作;当前对象未创建时,通过synchronized关键字同步代码块,持有当前Singleton.class的锁,保证线程安全,然后进行第二次检查。
4)、Singleton类持有的singleton实例引用需要volatile关键字修饰,因为在最后一步singleton = new Singleton(); 创建实例的时候可能会重排序,导致singleton对象逸出,导致其他线程获取到一个未初始化完毕的对象。
4、静态内部类实现单例
(1)可以延迟加载;
(2)基于 classloader 机制避免了多线程的同步问题,线程安全;没有性能缺陷;
public class Singleton{
private Singleton(){
}
public static Singleton newInstance(){
return SingletonHelper.instance;
}
//静态内部类 唯一性 私有的
private static class SingletonHelper{
private final static Singleton instance = new Singleton();
}
}
5、使用 枚举实现单例
优点:
(1)不是延迟加载的;
(2)枚举实例的创建是线程安全的,并且在任何情况下都是一个单例;
public enum Singleton {
INSTANCE;
}
总结:
饿汉:无法对instance实例进行延迟加载。
懒汉:多线程并发条件下无法保证实例的唯一性。
懒汉线程安全:使用synchronized 关键字导致性能缺陷。
DCL:JVM即编译器指令导致重排序,导致实例可能不唯一。
静态内部类、枚举:延迟加载、线程安全、性能优势。
android中用到的单例模式举例:application、eventBus
public class MyApplication extends Application { private static MyApplication instance; public static MyApplication getInstance() { return instance; } @Override public void onCreate() { super.onCreate(); instance = this; } }
通过MyApplication.getInstance()获取MyApplication类;
二、builder模式---将复杂的对象构建分离
builder模式也叫建造者模式,是较为复杂的 创建型模式,它将客户端与包含多个组成部分(或部件)的复杂对象的创建过程分离。 builder模式的作用将一个复杂对象的构建与他的表示分离,使用者可以一步一步的构建一个比较复杂的对象。
使用场景:当构建一个对象需要很多参数的时候,并且参数的对象和类型不固定的时候。
//Product:被构建的复杂对象,包含多个组成部件
public class Product {
private String partA;
private String partB;
private String partC;
public String getPartA() {
return partA;
}
public void setPartA(String partA) {
this.partA = partA;
}
public String getPartB() {
return partB;
}
public void setPartB(String partB) {
this.partB = partB;
}
public String getPartC() {
return partC;
}
public void setPartC(String partC) {
this.partC = partC;
}
}
//Builder:它为创建一个产品Product对象的各个部件指定抽象接口
abstract class Builder {
protected Product product = new Product();//创建产品对象
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
//用于返回复杂的产品对象
public Product getResult() {
return product;
}
}
//ConcreateBulder:实现了Builder接口,实现各个部件的具体构造和装配方法
public class ConcreateBulder extends Builder {
@Override
public void buildPartA() {
}
@Override
public void buildPartB() {
}
@Override
public void buildPartC() {
}
}
//指挥类:作用:隔离程序员创建复杂对象的过程;控制产品创建复杂对象的过程
//Director:指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系。
public class Director {
public Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void setBuilder(Builder builder) {
this.builder = builder;
}
//产品构建和组装的方法
public Product construct() {
builder.buildPartA();
builder.buildPartB();//每一个部分可以灵活选择是否实现
builder.buildPartC();
return builder.product;
}
}
//调用类:
class BuildClient{
public static void main(String[] args){
Builder builder = new ConcreateBulder();
Director director = new Director(builder);
director.construct();
}
}
总结:
(1)Product:被构建的复杂对象,包含多个组成部件
(2)Builder:它为创建一个产品Product对象的各个部件指定抽象接口
(3)ConcreateBulder:实现了Builder接口,实现各个部件的具体构造和装配方法
(4)Director:指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系。
优点:
松散耦合:生成器模式可以用同一个构造算法构建出表现上完全不同的产品,实现产品构建和产品表现上的分离。
可以很容易的改变产品的内部展示。
更好的复用性:生成器模式很好的实现构建算法和具体产品实现的分离。
缺点:
会产生多余的builder对象以及director对象,消耗内存。
对象的构建过程会暴露。
builder模式在android中的应用:AlertDialog、
三、adapter设计模式
定义:将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器。
1.类适配器:把适配的类的API转换成目标类的API。
让 Adapter
实现 Target
接口,并且 继承 Adaptee
,这样 Adapter
就具备 Target
和 Adaptee
可以将两者进行转化。
//目标角色:所期待得到的接口,类适配器目标不能为类
public interface Target {
void sampleOperation2();
}
//源角色:现在需要适配的接口,
public class Adaptee {
public void sampleOperation1(){
System.out.println("打印1212");
}
}
//适配器角色:适配器类是本模式的核心,适配器把源接口转换成目标接口,这一角色必须是类
public class Adapter extends Adaptee implements Target {
@Override
public void sampleOperation2() {
super.sampleOperation1();
}
}
public class Client {
public static void main(String[] args) {
Target target = new Adapter();
target.sampleOperation2();
}
}
总结:
1、类适配器使用对象继承的方式,是静态的定义方式。
2、对于类适配器,适配器可以重定义adapteree的部分行为。
3、对于类适配器,仅仅引用了一个对象,并不需要额外的引用来间接获得adapteree.
4、由于适配器直接继承了adapteree,使得适配器不能和adapteree的子类一起工作。
2.对象适配器模式:
对象适配器的原理就是通过组合来实现适配器功能,是动态组合的方式。具体做法:让Adapter 实现 Target 接口,然后内部持有 Adaptee 实例,然后再 Target 接口规定的方法内转换 Adaptee。 具体代码实现很简单就是将Adapter代码修改一下,原来是继承 Adaptee,现在是持有 Adaptee。
public interface Target {
void sampleOperation2();
}
public class Adaptee {
public void sampleOperation1(){
System.out.println("打印1212");
}
}
public class Adapter implements Target {
public Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void sampleOperation2() {
adaptee.sampleOperation1();
}
}
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Adapter adapter = new Adapter(adaptee);
adapter.sampleOperation2();
}
}
四、装饰模式
定义:动态地给对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类实现更加灵活,装饰模式是一种对象结构型模式。
使用场景:
1)在不影响其它对象的情况下,以动态、透明的方式给单个对象添加新的行为或特征
2)当不能采用继承的方式对系统进行扩展或采用继承不利于系统的扩展和维护时,采用装饰模式。
代码:
//抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。 人:吃、跑
public interface People {
void run();
void eat();
}
//具体构件(Concrete Component)角色:定义一个将要接收附加责任的类
public class Xiaoming implements People{
@Override
public void run() {
System.out.println("小明正在跑步。。。");
}
@Override
public void eat() {
System.out.println("小明正在吃饭。。。");
}
}
//装饰(Decorator)角色:持有一个构件(Component)对象的实例,并实现一个与抽象构件接口一致的接口。
public abstract class PeopleDetail implements People {
private People people;
public PeopleDetail(People people) {
this.people = people;
}
@Override
public void run() {
beforeRun();
people.run();
afterRun();
}
@Override
public void eat() {
beforeEat();
people.eat();
afterEat();
}
public abstract void beforeEat();
public abstract void afterEat();
public abstract void beforeRun();
public abstract void afterRun();
}
//具体装饰(Concrete Decorator)角色:负责给构件对象添加上附加的责任。
public class XiaomingRun extends PeopleDetail{
public XiaomingRun(People people) {
super(people);
}
@Override
public void beforeEat() {
}
@Override
public void afterEat() {
}
@Override
public void beforeRun() {
System.out.println("小明先做拉伸训练");
}
@Override
public void afterRun() {
System.out.println("小明进入慢走路状态");
}
}
//具体装饰(Concrete Decorator)角色:负责给构件对象添加上附加的责任。
public class XiaomingEat extends PeopleDetail{
public XiaomingEat(People people) {
super(people);
}
@Override
public void beforeEat() {
System.out.println("小明喝了一杯水");
}
@Override
public void afterEat() {
System.out.println("小明出去走了100步");
}
@Override
public void beforeRun() {
}
@Override
public void afterRun() {
}
}
//接下来进行测试:
public static void main(String[] args){
Xiaoming xiaoming = new Xiaoming();
System.out.println("小明开始吃饭--");
XiaomingEat xiaomingEat = new XiaomingEat(xiaoming);
xiaomingEat.eat();
System.out.println("小明开始跑步--");
XiaomingRun xiaomingRun =new XiaomingRun(xiaoming);
xiaomingRun.run();
}
优点:对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数急剧增加。降低了系统的耦合度;可以动态扩展一个实现类的功能。
五、外观模式
定义:主要目的在于让外部减少与子系统内部多个模块的交互,从而让外部能够更简单的使用子系统,它负责把客户端的请求转发给子系统内部的各个模块进行处理。
使用场景:
1)当你要为一个复杂子系统提供一个简单接口时。
2)客户程序与抽象类的实现部分之间存在着很大的依赖性。
3)当你需要构建一个有层次结构的子系统时。
//抽象的组件
public interface Module {
void work();
}
//实例
public class Module1 implements Module{
@Override
public void work() {
System.out.println("Module1");
}
}
public class Module2 implements Module{
@Override
public void work() {
System.out.println("Module2");
}
}
public class Module3 implements Module{
@Override
public void work() {
System.out.println("Module3"+"改变了");
}
}
public class ModuleImpl {
private Module1 module1 = null;
private Module3 module3= null;
private Module2 module2= null;
private static ModuleImpl moduleImpl = null;
private ModuleImpl(){
this.module1 = new Module1();
this.module2 = new Module2();
this.module3 = new Module3();
}
public static ModuleImpl getInstance(){
if (moduleImpl==null){
moduleImpl = new ModuleImpl();
}
return moduleImpl;
}
public void testModule(){
module1.work();
module2.work();
module3.work();
}
}
//测试:
ModuleImpl.getInstance().testModule();
优点:
1)由于ModuleImpl 封装了各个模块交互的过程,如果今后内部模块调用发生了变化,只需要修改ModuleImpl 类就可以。
2)ModuleImpl 是单例的,是可以被多个客户端调用的。
六、组合模式
定义:将对象以树形结构组织起来,以达成“部分-整体”的层次结构,使得客户端和单个对象和组合对象的使用具有一致性。
树的结构——>组合设计模式
使用场景:
1)需要表示一个对象整体或者部分层次。
2)让客户能够忽略不同对象层次的变化。
public abstract class File {
private String name;
public File(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void Watch();
//以下三个方法是组合方法
public void add(File file) {
throw new UnsupportedOperationException();
}
public void remove(File file) {
throw new UnsupportedOperationException();
}
public File getChild(int positon) {
throw new UnsupportedOperationException();
}
}
public class Folder extends File {
public List<File> mFileList;
public Folder(String name) {
super(name);
mFileList = new ArrayList<>();
}
@Override
public void Watch() {
StringBuffer fileName = new StringBuffer();
for (File file : mFileList) {
fileName.append(file.getName() + ":");
}
System.out.println("组合模式:"+"这是一个叫"+getName()+"文件夹,包含:"+mFileList.size()+"个文件,分别是:"+fileName);
}
@Override
public void add(File file) {
mFileList.add(file);
}
@Override
public void remove(File file) {
mFileList.remove(file);
}
@Override
public File getChild(int positon) {
return mFileList.get(positon);
}
}
public class TextFile extends File {
public TextFile(String name) {
super(name);
}
@Override
public void Watch() {
System.out.println("这是一个叫"+getName()+"的文件夹");
}
}
测试:
public static void main(String[] args){
TextFile textFileA =new TextFile("a.txt");
TextFile textFileB =new TextFile("b.txt");
TextFile textFileC =new TextFile("c.txt");
textFileA.Watch();
Folder folder = new Folder("组合设计模式");
folder.add(textFileA);
folder.add(textFileB);
folder.add(textFileC);
folder.Watch();
folder.getChild(1).Watch();
}
优点:高层模块调用简单;节点自由增加,案例中创建了两个子类,可以创建多个子类;
缺点:违反了依赖倒置原则;