android23种设计模式

来源:互联网 发布:柴鸡蛋逆袭网络剧下载 编辑:程序博客网 时间:2024/05/20 16:11

注:本篇博客是学自于Android源码设计模式(何红辉 关爱民) 但愿不会有侵权的行为。
一、单例模式
单例模式是最常用,且最基础的设计模式,顾名思义,单例,只允许存在一个。
UML图如下:
这里写图片描述
简单的分,单例模式分为两种:
1.饿汉式:
简而言之,进来就new一个对象,并保证对象唯一性。
代码如下:
public class SingleInstance{

/**   * 单例对象实例   */    private static SingleInstance instance = new SingleInstance();public static SingleInstance getInstance() {           return instance;    }    

}

2.懒汉式:
在需要的时候,才会new一个对象。
代码如下:
public class SingleInstance{

/**   * 单例对象实例   */    private static SingleInstance instance = null;  public static SingleInstance getInstance() {        if (instance == null) {                                          instance = new SingleInstance();                }        return instance;    }    

}
懒汉式有个问题,当是多线程同时访问时,会出现问题,假设两条线程同时访问,当线程1进入if判断instance==null,这是cpu资源被线程2抢到,同时也执行到if条件语句,instance==null,并new对象,当线程1唤醒后,继续走if{}代码块中的内容,也会new一个对象,这样就不会达到我们使用单例只创建一个对象的初衷了。而饿汉式进来就会直接new一个对象,是不会出现懒汉式这样的问题。
如果我们要用懒汉式,同时避免出现new多个对象,可以加入同步锁。
public class SingleInstance{

/**   * 单例对象实例   */    private static SingleInstance instance = null;  public synchronized static SingleInstance getInstance() {        if (instance == null) {                                          instance = new SingleInstance();                }        return instance;    }    

}此方法,同时只允许一个线程进行操作,可以避免创建多个对象的问题。
二、工厂模式
工厂模式,顾名思义,相当于一个工厂,不断地生产产品。java中则为不断的new对象。
理解:创建一个抽象产品类,一个实际产品继承抽象产品类,创建一个抽象工厂类,其下有一个生产抽象产品的抽象方法,一个具体工厂类继承抽象工厂类,并实现抽象工厂类的方法。如何使用呢?创建一个实际的工厂对象,赋值给抽象工厂类,接下来就可以调用这个实际的工厂对象下的方法,不断的获取我们想要的对象。
UML图如下:
这里写图片描述
实现原理:
定义一个用于创建对象的接口,让子类去实现此接口,决定实例化哪个类。
工厂模式中的四大角色:
1、抽象工厂:工厂方法模式的核心,任何在模式中创建对象的工厂类必须实现这个接口。
2、具体工厂:实现了抽象工厂接口的具体JAVA类。具体工厂角色含有与业务密切相关的逻辑,并且受到使用者的调用以创建导出类。
3、抽象角色:工厂方法模式所创建的对象的超类。
4、具体角色:实现抽象角色的某个具体角色的实例。
具体实现如下:
1.定义一个抽象类
public abstact class{
public String getInstance();
}
2.定义具体实现类
public class BasketBall implements Ball{
@Override
public String getInstance() {
return “篮球”;
}
}
public class FootBall implements Ball{
@Override
public String getInstance() {
return “足球”;
}
}
3.抽象工厂接口(重点)
public interface BallFactory {
public Ball getBall();
}
4.具体工厂
publicclassBasketBallFactoryimplements BallFactory {

@OverridepublicBall getBall {    returnnew BasketBall();}

}
public class FootBallFactory implements BallFactory {

@OverridepublicBall getBall {    returnnew FootBall();}

}

5.在java代码中使用工厂模式
public class UseFactory {
public void use()
{
//若是需要修改,只需要修改 new FootBallFactory (); 即可;
BallFactory factory= new BasketBallFactory ();
// 使用工厂模式,调用者只关心产品的接口就可以了,
//至于具体的实现,调用者根本无需关心。即使变更了具体的实现,对调用者来说没有任何影响。
BasketBall basketBall= factory.getBall();
}
}
三、抽象工厂模式
抽象工厂模式,比工厂模式多了一个抽象,其实,就相当于把工厂模式更加抽象化了。工厂模式是一个抽象的工厂,可以创建一类产品,而抽象工厂模式,是多组工厂,创建多组产品。
UML图如下:
这里写图片描述
1.抽象产品A
public abstact class ProductA{
public void method();
}
2.抽象产品B
public abstact class ProductB{
public abstract void method();
}
3.具体产品A1、A2
public class A1 extends ProductA{
@Override
public void method(){}
public class A2 extends ProductA{
@Override public void method(){}
4.具体产品B1、B2
public class B1 extends ProductB{
@Overrid
public void method(){
}
}
public class B2 extends ProductB{
@Overrid
public void method(){
}
}
5、抽象工厂类
public abstract class AbstractFatory{
public abstract ProductA getProductA();//创建ProductA类产品
public abstract ProductB getProductB();//创建ProductB类产品
}
6.具体工厂类A
public class ProductAFactory extends AbstractFactory{
@Override
oublic ProductA getProductA(){
return new A1();
}
@Override
public ProductB getProductB(){
return new B1();
}
7.具体工厂类B
public class ProductBFactory extends AbstractFactory{
@Override
public ProductA getProductA(){
return new A2();
}
public ProductB getProductB(){
return new B2();
}
8.使用
AbstractFatory factory=new ProductAFactory();
A1 a1=factory.getProductA();
a1.method();
B1 b1=factory.getProductB();
b1.method();
总结:抽象工厂模式比工厂模式繁琐,android项目中用到的几率也很小,但是我们要懂其中的原理。

四、装饰者模式
也可以称之为包装模式,动态的给对象增加一些额外的功能,类似于定义一个抽象类,由子类实现抽象类中的方法,同时可以添加子类自己的方法,达到扩展功能的效果。
UML图如下:
这里写图片描述
在装饰模式中的各个角色有:
1、抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象
2、具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。
3、装饰(Decorator)角色:持有一个构件(Component)对象的实例,并实现一个与抽象构件接口一致的接口
4、具体装饰(Concrete Decorator)角色:负责给构件对象添加上附加的责任。
/*
* 抽象组件类
* */
public abstract class Person{
/*
* 穿着方法
* */
public abstract void dressed();
}
public class Boy extends Person{

    @Override    public void dressed() {        System.out.print("穿内衣");    }}/*** Boy类继承Person类 实现了其穿着方法 ,Boy类就是我们要装饰的具体对象,现在需要一个装饰折来装饰Boy对象 下面定义一个PersonCloth类来标识人所穿着的衣服* */public abstract  class PersonCloth extends Person{    protected Person person;//保持一个Person类的引用    public PersonCloth( Person person){        this.person=person;    }    @Override    public  void dressed(){        //调用Person类中的dressed方法        person.dressed();    }}</span></span>

public class ExpensiveCloth extends PersonCloth{

    public ExpensiveCloth(Person person) {        super(person);    }    private void dressShirt(){        System.out.print("穿短袖");    }    private void dressJean(){        System.out.print("穿牛仔");    }    @Override    public  void dressed(){        super.dressed();        dressJean();        dressShirt();    }}public class CheapCloth extends PersonCloth{    public CheapCloth(Person person) {        super(person);    }    private void dressShort(){        System.out.print("穿便宜的短袖");    }    @Override    public  void dressed(){        super.dressed();        dressShort();    }

}
使用:
Person person=new Boy();
PersonCloth clothCheap=new CheapCloth(person)
clothCheap.dressed();
PersonCloth clothExpersive=new ExpensiveCloth (person);
clothExpersive.dressed();
五、Builder构建者模式
将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。(AlertDialog就是典型的构建者模式)
1、 builder:为创建一个产品对象的各个部件指定抽象接口。
2 、ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并 提供一个检索产品的接口。
3 、Director:构造一个使用Builder接口的对象。
4 、Product:表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
UML图:
这里写图片描述

package com.dp.example.builder;

/**
* Computer产品抽象类, 为了例子简单, 只列出这几个属性
*
* @author mrsimple
*
*/
public abstract class Computer {

protected int mCpuCore = 1;
protected int mRamSize = 0;
protected String mOs = “Dos”;

protected Computer() {

}

// 设置CPU核心数
public abstract void setCPU(int core);

// 设置内存
public abstract void setRAM(int gb);

// 设置操作系统
public abstract void setOs(String os);

@Override
public String toString() {
return “Computer [mCpuCore=” + mCpuCore + “, mRamSize=” + mRamSize
+ “, mOs=” + mOs + “]”;
}

}

package com.dp.example.builder;

/**
* Apple电脑
* @author mrsimple
*
*/
public class AppleComputer extends Computer {

protected AppleComputer() {

}

@Override
public void setCPU(int core) {
mCpuCore = core;
}

@Override
public void setRAM(int gb) {
mRamSize = gb;
}

@Override
public void setOs(String os) {
mOs = os;
}

}

package com.dp.example.builder;

/**
* builder抽象类
*
* @author mrsimple
*
*/
public abstract class Builder {
// 设置CPU核心数
public abstract void buildCPU(int core);

// 设置内存
public abstract void buildRAM(int gb);

// 设置操作系统
public abstract void buildOs(String os);

// 创建Computer
public abstract Computer create();

}

package com.dp.example.builder;

/**
* Apple电脑
* @author mrsimple
*
*/
public class AppleComputer extends Computer {

protected AppleComputer() {

}

@Override
public void setCPU(int core) {
mCpuCore = core;
}

@Override
public void setRAM(int gb) {
mRamSize = gb;
}

@Override
public void setOs(String os) {
mOs = os;
}

}

package com.dp.example.builder;

/**
* builder抽象类
*
* @author mrsimple
*
*/
public abstract class Builder {
// 设置CPU核心数
public abstract void buildCPU(int core);

// 设置内存
public abstract void buildRAM(int gb);

// 设置操作系统
public abstract void buildOs(String os);

// 创建Computer
public abstract Computer create();

}

package com.dp.example.builder;

public class ApplePCBuilder extends Builder {
private Computer mApplePc = new AppleComputer();

@Override
public void buildCPU(int core) {
mApplePc.setCPU(core);
}

@Override
public void buildRAM(int gb) {
mApplePc.setRAM(gb);
}

@Override
public void buildOs(String os) {
mApplePc.setOs(os);
}

@Override
public Computer create() {
return mApplePc;
}

}

package com.dp.example.builder;

public class Director {
Builder mBuilder = null;

/**
*
* @param builder
*/
public Director(Builder builder) {
mBuilder = builder;
}

/**
* 构建对象
*
* @param cpu
* @param ram
* @param os
*/
public void construct(int cpu, int ram, String os) {
mBuilder.buildCPU(cpu);
mBuilder.buildRAM(ram);
mBuilder.buildOs(os);
}
}

/**
* 经典实现较为繁琐
*
* @author mrsimple
*
*/
public class Test {
public static void main(String[] args) {
// 构建器
Builder builder = new ApplePCBuilder();
// Director
Director pcDirector = new Director(builder);
// 封装构建过程, 4核, 内存2GB, Mac系统
pcDirector.construct(4, 2, “Mac OS X 10.9.1”);
// 构建电脑, 输出相关信息
System.out.println(“Computer Info : ” + builder.create().toString());
}
}
六、原型模式
本质上,就是对象的拷贝。原型一个要被克隆的对象,叫做原型,原型需要实现Cloneable接口,才能保证可以被克隆
UML图:
这里写图片描述
角色分析:
Client:客户端用户
Prototpe:抽象类或者接口,要有被clone的能力
ConcretePrototype:具体的原型类
package com.dp.example.builder;

package com.dp.example.prototype;

import java.util.ArrayList;
import java.util.List;

/**
* 文档类型, 扮演的是ConcretePrototype角色,而cloneable是代表prototype角色
*
* @author mrsimple
*/
public class WordDocument implements Cloneable {
/**
* 文本
*/
private String mText;
/**
* 图片名列表
*/
private ArrayList mImages = new ArrayList();

public WordDocument() {    System.out.println("----------- WordDocument构造函数 -----------");}/** * 克隆对象 */@Overrideprotected WordDocument clone() {    try {        WordDocument doc = (WordDocument) super.clone();        doc.mText = this.mText;        doc.mImages = this.mImages;        return doc;    } catch (Exception e) {    }    return null;}public String getText() {    return mText;}public void setText(String mText) {    this.mText = mText;}public List<string> getImages() {    return mImages;}/** * @param img */public void addImage(String img) {    this.mImages.add(img);}/** * 打印文档内容 */public void showDocument() {    System.out.println("----------- Word Content Start -----------");    System.out.println("Text : " + mText);    System.out.println("Images List: ");    for (String imgName : mImages) {        System.out.println("image name : " + imgName);    }    System.out.println("----------- Word Content End -----------");}

}
通过WordDocument类模拟了word文档中的基本元素,即文字和图片。WordDocument的在该原型模式示例中扮演的角色为ConcretePrototype, 而Cloneable的角色则为Prototype。WordDocument实现了clone方法以实现对象克隆。下面我们看看Client端的使用 :
public class Client {
public static void main(String[] args) {
WordDocument originDoc = new WordDocument();
originDoc.setText(“这是一篇文档”);
originDoc.addImage(“图片1”);
originDoc.addImage(“图片2”);
originDoc.addImage(“图片3”);
originDoc.showDocument();
WordDocument doc2 = originDoc.clone();
doc2.showDocument();
doc2.setText(“这是修改过的Doc2文本”);
doc2.showDocument();
originDoc.showDocument();
}
}
doc2是通过originDoc.clone()创建的,并且doc2第一次输出的时候和originDoc输出是一样的。即doc2是originDoc的一份拷贝,他们的内容是一样的,而doc2修改了文本内容以后并不会影响originDoc的文本内容。需要注意的是通过clone拷贝对象的时候并不会执行构造函数!
浅拷贝和深拷贝

将main函数的内容修改为如下 :
public static void main(String[] args) {
WordDocument originDoc = new WordDocument();
originDoc.setText(“这是一篇文档”);
originDoc.addImage(“图片1”);
originDoc.addImage(“图片2”);
originDoc.addImage(“图片3”);
originDoc.showDocument();
WordDocument doc2 = originDoc.clone();
doc2.showDocument();
doc2.setText(“这是修改过的Doc2文本”);
doc2.addImage(“哈哈.jpg”);
doc2.showDocument();
originDoc.showDocument();
}
细心的朋友可能发现了,在doc2添加了一张名为”哈哈.jpg”的照片,但是却也显示在originDoc中?这是怎么回事呢? 其实学习过C++的朋友都知道,这是因为上文中WordDocument的clone方法中只是简单的进行浅拷贝,引用类型的新对象doc2的mImages只是单纯的指向了this.mImages引用,而并没有进行拷贝。doc2的mImages添加了新的图片,实际上也就是往originDoc里添加了新的图片,所以originDoc里面也有”哈哈.jpg” 。那如何解决这个问题呢? 那就是采用深拷贝,即在拷贝对象时,对于引用型的字段也要采用拷贝的形式,而不是单纯引用的形式。示例如下 :
/**
* 克隆对象
*/
@Override
protected WordDocument clone() {
try {
WordDocument doc = (WordDocument) super.clone();
doc.mText = this.mText;
// doc.mImages = this.mImages;
doc.mImages = (ArrayList) this.mImages.clone();
return doc;
} catch (Exception e) {
}
return null;
}

如上代码所示,将doc.mImages指向this.mImages的一份拷贝, 而不是this.mImages本身,这样在doc2添加图片时并不会影响originDoc。
源码分析
在Android源码中,我们以熟悉的Intent来分析源码中的原型模式。简单示例如下 :
Uri uri = Uri.parse(“smsto:0800000123”);
Intent shareIntent = new Intent(Intent.ACTION_SENDTO, uri);
shareIntent.putExtra(“sms_body”, “The SMS text”);
Intent intent = (Intent)shareIntent.clone() ;
startActivity(intent);
可以看到,我们通过shareIntent.clone方法拷贝了一个对象intent, 然后执行startActivity(intent), 随即就进入了短信页面,号码为0800000123,文本内容为The SMS text,即这些内容都与shareIntent一致。
下面我们看看Intent的clone的实现 :
@Override
public Object clone() {
return new Intent(this);
}

/**
* Copy constructor.
*/
public Intent(Intent o) {
this.mAction = o.mAction;
this.mData = o.mData;
this.mType = o.mType;
this.mPackage = o.mPackage;
this.mComponent = o.mComponent;
this.mFlags = o.mFlags;
if (o.mCategories != null) {
this.mCategories = new ArraySet(o.mCategories);
}
if (o.mExtras != null) {
this.mExtras = new Bundle(o.mExtras);
}
if (o.mSourceBounds != null) {
this.mSourceBounds = new Rect(o.mSourceBounds);
}
if (o.mSelector != null) {
this.mSelector = new Intent(o.mSelector);
}
if (o.mClipData != null) {
this.mClipData = new ClipData(o.mClipData);
}
}
可以看到,clone方法实际上在内部调用了new Intent(this); 这就和C++中的拷贝构造函数完全一致了,而且是深拷贝。

0 0
原创粉丝点击