1.单例模式
单例模式存在的意义主要就是保证有且仅有一个对象,只创建一个,所有想要拿到该单例的都是同一个对象。
单例模式的好处:
1).由于单例模式在内存中只有一个实例,减少了内存开销。对于那些耗内存的类,只实例化一次,大大提高性能,尤其是移动开发中。
2).单例模式可以避免对资源的多重占用,例如一个写文件时,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
3).单例模式可以在系统设置全局的访问点,优化和共享资源访问。
总结了一下单例模式的实现,大概分为四种:饿汉式,懒汉式,双重校验锁,静态内部类。
分别来看一下他们的实现,直接上代码:
(1)饿汉式:
public class EHanSingleton {
//在类初始化时,已经自行实例化,所以是线程安全的。
private static final EHanSingleton single =new EHanSingleton();
public static EHanSingleton getInstance(){
return single;
}
}
饿汉式写法简单,线程安全,在类初始化时就已经创建了实例对象,但没有懒加载的效果,如果没有使用会造成不必要的内存浪费。
(2)懒汉式:
public class LanHanSingleton {
private static LanHanSingleton singleton;
public static synchronized LanHanSingleton getSingleton(){
if (singleton == null){
singleton =new LanHanSingleton();
}
return singleton;
}
}
懒汉式实现了懒加载效果,将创建实例对象放在了同步方法中,避免了不必要的内存浪费,但因为使用了synchronized方法,会造额外的同步开销。
(3)双重校验锁:
public class DoubleCheckSingleton {
private volatile static DoubleCheckSingleton singleton;
public static DoubleCheckSingleton getInstance(){
if (singleton == null){
synchronized (DoubleCheckSingleton.class){
if (singleton == null){
singleton =new DoubleCheckSingleton();
}
}
}
return singleton;
}
}
双重校验锁通过双重校验避免了不必要的同步开销,实现了懒加载,线程安全,效率较前两个较高,但volatile会影响一点性能,高并发下有一定的缺陷,某些情况下DCL会失效,虽然概率较小。
(4)静态内部类:
public class StaticInnerSigleton {
public static StaticInnerSigleton getInstance(){
return StaticInner.single;
}
//静态内部类
private static class StaticInner{
private static final StaticInnerSigleton single =new StaticInnerSigleton();
}
}
静态内部类实现了懒加载,线程安全,这里推荐使用。
2.工厂模式
工厂设计模式是一种创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
在面向对象编程中,最常用的方法是new一个操作符产生一个对象实例,new对象操作符就是用来构造对象实例的,但是在一些情况下,new操作符直接生成对象会带来一些问题,举例说,许多类型对象的创建都需要一系列的步骤,可能需要计算或取得对象的初始设置,选择生成哪个子对象实例,或者在生成需要的对象之前必须先生成一些辅助功能的对象,这些情况下,对象的建立就是一个过程,不仅是一个操作。
那么怎么能够方便的构建对象实例,而不关心构造对象实例的细节和复杂过程呢,那就是建立一个工厂来创建对象。把创建的过程封装到工厂里。
工厂模式在Android开发中也经常能见到,例如我们创建Android自带网络请求类HttpUrlConnetion时,不是直接new出来一个HttpUrlConnection,而是通过url.OpenConnection来创建HttpUrlConnection的实例。
工厂模式的种类一共有三种:简单工厂模式,工厂方法模式,抽象工厂模式。一般将简单工厂模式看作工厂方法的体例,二者归为一类。
(1)简单工厂模式:
简单工厂模式分为三个角色,抽象产品角色,具体产品角色,工厂类角色。
抽象产品角色,一般是具体产品继承的父类或者实现的接口:
//产品类
abstract class BMW{
public BMW(){}
}
工厂类所创建的对象就是具体产品角色,在java中由一个具体类实现:
//具体产品类
public class BMW100 extends BMW{
public BMW100(){
System.out.println("this is BMW100");
}
}
public class BMW200 extends BMW{
public BMW200(){
System.out.println("this is BMW200");
}
}
工厂类角色是本模式的核心,含有一定的商业逻辑和判断逻辑,用来创建产品:
//工厂类
public class Factory{
public BMW CreateBMW(int type){
if(type ==100) return new BMW100();
if(type ==200) return new BMW200();
else return null;
}
}
在简单工厂中,当客户不再满足现有的车型号时,想要一种更快的车,只要这种车满足抽象产品指定的规则,只要通知工厂类增加相应的逻辑就好了,但是每增加一种车,都要在工厂类中增加相应的逻辑,工厂类十分被动,这样的工厂类成为全能类或者上帝类。
(2)工厂方法模式
工厂方法模式主要是将简单工厂模式的工厂类分为抽象工厂类和具体工厂类。
抽象产品角色具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现:
//抽象产品类
abstract class BMW()
{
public BMW();
}
具体产品角色,具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现:
// 具体产品类 四种车,宝马1系,(两种),2系(两种)
public class BMW100 extends BMW
{
public BMW100()
{
System.out.println("this is BMW100");
}
}
public class BMW109 extends BMW
{
public BMW109()
{
System.out.println("this is BMW100");
}
}
public class BMW200 extends BMW
{
public BMW200()
{
System.out.println("this is BMW200");
}
}
public class BMW209 extends BMW
{
public BMW209()
{
System.out.println("this is BMW209");
}
}
抽象工厂角色是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现:
//抽象工厂角色
interface Factory
{
BMW createBMW();
}
具体工厂角色含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象:
//具体工厂角色
public class FactoryBMW1 implements FactoryBMW{
@Override
public BMW100 createBMW() {
return new BMW100();
}
}
public class FactoryBMW2 implements FactoryBMW {
@Override
public BMW200 createBMW() {
return new BMW200();
}
} //分为100的工厂和200的工厂(省略了两个工厂)。都实现了工厂的接口
想加一辆车,就单独加车的类,这个车的工厂,然后只修改客户端的代码即可。工厂方法模式实现时,客户端需要决定实例化哪一个工厂来创建对象,工厂方法把简单工厂的内部逻辑移到了客户端代码来执行。
(3)抽象工厂模式
抽象工厂模式是工厂方法模式的升级版本,它用来创建一组相关或者相互依赖的对象。
抽象工厂模式提供一个创建一系列相关或者相互依赖对象的接口,而无需指定他们具体的类。就是一个工厂里放一些相关的类,使工厂数减少。
最大的好处便是易于交换产品系列,其次是让具体的创建实例过程与客户端分离,客户端通过他们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离。不会出现在客户代码中。
抽象工厂方法就是一个工厂里生产不同等级结构中的一个(其中一种车)中的不同的配件(不同的车的属性):
//抽象产品类1 发动机以及型号
public interface Engine {
}
//抽象产品类2 空调以及型号
public interface Aircondition {
}
//具体产品类
public class EngineA extends Engine{
public EngineA(){
System.out.println("制造-->EngineA");
}
}
public class EngineB extends Engine{
public EngineB(){
System.out.println("制造-->EngineB");
}
}
public class AirconditionA extends Aircondition{
public AirconditionA(){
System.out.println("制造-->AirconditionA");
}
}
public class AirconditionB extends Aircondition{
public AirconditionB(){
System.out.println("制造-->AirconditionB");
}
}
//抽象工厂
public interface AbstractFactory {
//制造发动机
public Engine createEngine();
//制造空调
public Aircondition createAircondition();
}
//具体工厂类
public class 奔驰工厂 implements AbstractFactory{
@Override
public Engine createEngine() {
return new EngineA();
}
@Override
public Aircondition createAircondition() {
return new AirconditionA();
}
}
//为宝马车生产配件
public class 宝马工厂 implements AbstractFactory {
@Override
public Engine createEngine() {
return new EngineB();
}
@Override
public Aircondition createAircondition() {
return new AirconditionB();
}
}
抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
3.建造者模式
建造者模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式在android开发中也经常见到,比如常见的对话框创建和Okhttp等。
AlertDialog.Builder builder=new AlertDialog.Builder(this);
AlertDialog dialog=builder.setTitle("对话框")
.setIcon(android.R.drawable.ic_dialog)
.setView(R.layout.custom_view)
.setPositiveButton(R.string.positive, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setNegativeButton(R.string.negative, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.create();
dialog.show();
Request.Builder builder=new Request.Builder();
Request request=builder.addHeader("","")
.url("")
.post(body)
直接上建造者模式的代码:
public class UserInfo {
private String name;
private int age;
private double height;
private double weight;
private UserInfo(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.height = builder.height;
this.weight = builder.weight;
}
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 double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
static class Builder {
private String name;
private int age;
private double height;
private double weight;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder height(double height) {
this.height = height;
return this;
}
public Builder weight(double weight) {
this.weight = weight;
return this;
}
public UserInfo build() {
return new UserInfo(this);
}
}
}
Request.Builder builder=new Request.Builder();
Request request=builder.addHeader("","")
.url("")
.post(body)
总结一下建造者模式的优点:
- 封装性:使用建造者模式可以是客户端不必知道产品内部组成的细节。
- 建造者独立,容易扩展。
- 便于控制细节风险:由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块穿上任何影响。
建造者模式关注的是零件类型和装配工艺(顺序),这是它与工厂方法模式最大不同的 地方,虽然同为创建类模式,但是注重点不同。
3.观察者模式
观察者模式定义对象间一种一对多的依赖关系,使得当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
主要包括四个部分:
1. Subject被观察者。是一个接口或者是抽象类,定义被观察者必须实现的职责,它必须能偶动态地增加、取消观察者,管理观察者并通知观察者。
2. Observer观察者。观察者接收到消息后,即进行update更新操作,对接收到的信息进行处理。
3. ConcreteSubject具体的被观察者。定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。
4. ConcreteObserver具体观察者。每个观察者在接收到信息后处理的方式不同,各个观察者有自己的处理逻辑。
在Android开发中也经常见到观察者模式的身影,如广播,EventBus等。
下面我们模拟场景:天气预报,每次天气更新都会向你及时发送消息,观察者们就要更新界面。写法如下:
首先是一个天气的基本类:
public class Weather {
private String description;
public Weather(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "Weather{" +
"description='" + description + '\'' +
'}';
}
}
然后定义被观察者,我们希望它能够通用,所以定义成泛型,内部应该暴露出register和unRegister供观察者订阅和取消订阅,至于观察者的保存,我们用ArrayList即可,另外,当主题发生变化的时候,需要通知观察者来做出响应,还需要一个notifyObservers方法,具体实现如下:
public class Observable<T> {
List<Observer<T>> mObservers = new ArrayList<Observer<T>>();
public void register(Observer<T> observer) {
if (observer == null) {
throw new NullPointerException("observer == null");
}
synchronized (this) {
if (!mObservers.contains(observer))
mObservers.add(observer);
}
}
public synchronized void unregister(Observer<T> observer) {
mObservers.remove(observer);
}
public void notifyObservers(T data) {
for (Observer<T> observer : mObservers) {
observer.onUpdate(this, data);
}
}
}
我们的观察者只需要实现一个观察者的接口Observer,该接口也是泛型的:
public interface Observer<T> {
void onUpdate(Observable<T> observable,T data);
}
最后是调用:
public class Main {
public static void main(String [] args){
Observable<Weather> observable=new Observable<Weather>();
Observer<Weather> observer1=new Observer<Weather>() {
@Override
public void onUpdate(Observable<Weather> observable, Weather data) {
System.out.println("观察者1:"+data.toString());
}
};
Observer<Weather> observer2=new Observer<Weather>() {
@Override
public void onUpdate(Observable<Weather> observable, Weather data) {
System.out.println("观察者2:"+data.toString());
}
};
observable.register(observer1);
observable.register(observer2);
Weather weather=new Weather("晴转多云");
observable.notifyObservers(weather);
Weather weather1=new Weather("多云转阴");
observable.notifyObservers(weather1);
observable.unregister(observer1);
Weather weather2=new Weather("台风");
observable.notifyObservers(weather2);
}
}
这样一来当被观察者通知天气更新时,所有注册的观察者就会自动更新天气信息了。
好了,几种常用的设计模式就介绍到这里了。
乘风破浪会有时,直挂云帆济沧海!
参考文章: