设计模式学习笔记--单例、建造者、适配器、装饰、外观、组合
创始人
2024-05-25 13:18:24
0

以下内容根据以下网址及相关视频整理:Android设计模式之单例模式_谬谬清不给我取名字的博客-CSDN博客_android 单例模式

Android设计模式--单例模式的六种实现和单例模式讲解Volatile与Synchronized相关的并发_龙腾腾的博客-CSDN博客_android 单例 volatile

java 设计模式实战,装饰者模式之不用改变也能变强 - 掘金

目录

一、单例模式:

1、饿汉式单例模式:

2、懒汉式单例模式:

3、双重检索(Double Check Lock,DCL)

4、静态内部类实现单例

5、使用 枚举实现单例

二、builder模式---将复杂的对象构建分离

三、adapter设计模式

1.类适配器:把适配的类的API转换成目标类的API。

2.对象适配器模式:

四、装饰模式

五、外观模式

六、组合模式


一、单例模式:

(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;}@Overridepublic 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 {@Overridepublic void buildPartA() {}@Overridepublic void buildPartB() {}@Overridepublic 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 {@Overridepublic 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;}@Overridepublic 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{@Overridepublic void run() {System.out.println("小明正在跑步。。。");}@Overridepublic void eat() {System.out.println("小明正在吃饭。。。");}
}//装饰(Decorator)角色:持有一个构件(Component)对象的实例,并实现一个与抽象构件接口一致的接口。
public abstract class PeopleDetail implements People {private People people;public PeopleDetail(People people) {this.people = people;}@Overridepublic void run() {beforeRun();people.run();afterRun();}@Overridepublic 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);}@Overridepublic void beforeEat() {}@Overridepublic void afterEat() {}@Overridepublic void beforeRun() {System.out.println("小明先做拉伸训练");}@Overridepublic void afterRun() {System.out.println("小明进入慢走路状态");}
}//具体装饰(Concrete Decorator)角色:负责给构件对象添加上附加的责任。
public class XiaomingEat extends PeopleDetail{public XiaomingEat(People people) {super(people);}@Overridepublic void beforeEat() {System.out.println("小明喝了一杯水");}@Overridepublic void afterEat() {System.out.println("小明出去走了100步");}@Overridepublic void beforeRun() {}@Overridepublic 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{@Overridepublic void work() {System.out.println("Module1");}
}public class Module2 implements Module{@Overridepublic void work() {System.out.println("Module2");}
}public class Module3 implements Module{@Overridepublic 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 mFileList;public Folder(String name) {super(name);mFileList = new ArrayList<>();}@Overridepublic void Watch() {StringBuffer fileName = new StringBuffer();for (File file : mFileList) {fileName.append(file.getName() + ":");}System.out.println("组合模式:"+"这是一个叫"+getName()+"文件夹,包含:"+mFileList.size()+"个文件,分别是:"+fileName);}@Overridepublic void add(File file) {mFileList.add(file);}@Overridepublic void remove(File file) {mFileList.remove(file);}@Overridepublic File getChild(int positon) {return mFileList.get(positon);}
}public class TextFile extends File {public TextFile(String name) {super(name);}@Overridepublic 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();}

 优点:高层模块调用简单;节点自由增加,案例中创建了两个子类,可以创建多个子类;

缺点:违反了依赖倒置原则;

 

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...