Java[Android]设计模式创建型设计模式之Builder模式+单例模式+原型模式

1. 写在前面

写博客纯属为自己记一个笔记方便自己以后查看,希望对路过的朋友有帮助;若有偏颇请朋友及时指正。

本文主要介绍在创建型设计模式中的Builder模式、单单例模式和原型模式。

2. Builder模式

Builder模式是把一个复杂对象的构造过程与表示分离,使用户利用同样的调用过程可以创建出符合条件的不同对象,在实际使用过程中我们一般采用链式调用的方式使代码简洁可读性很强。

2.1 UML类图

从UML图可以看出Builder模式中有以下几种模式:

Builder角色:为创建一个Product对象的各个属性指定抽象接口(包括最终生成对象的接口定义)。

实际Builder(ConcreteBuilder):实现Builder的接口以构造和装配该产品的各个部件;在实际代码中通常会在其中定义一个内部类(ProductParams)来表示Product产品的各个部件(属性part1,part2),然后在最后的build方法中利用这个内部类构造出Product对象。

Director 构造一个使用Builder接口的对象,有时候在实际开发中可能会省略或者由具有其它功能的类来代替。

Product 表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的创建过程。

2.2 代码示例

Builder类:

public interface Builder {
	public Builder makePart1(String part1);
	public Builder makePart2(String part2);
	public Product build();
}

ConcreteBuilder:

public class ConcreteBuilder implements Builder {
	private ProductParams params;
	
	public ConcreteBuilder() {
		this.params = new ProductParams();
	}
	
	@Override
	public Builder makePart1(String part1) {
		this.params.part1 = part1;
		return this;
	}

	@Override
	public Builder makePart2(String part2) {
		this.params.part2 = part2;
		return this;
	}

	@Override
	public Product build() {
		Product product = new Product();
		product.setPart1(params.part1);
		product.setPart2(params.part2);
		return product;
	}
	
	class ProductParams {
		public  String part1;
        public String part2;
	}
}

Product类:

public class Product {
	private String part1;
	private String part2;
	
	public Product() {
	}
	
	public Product(String part1, String part2) {
		this.part1 = part1;
		this.part2 = part2;
	}

	public String getPart1() {
		return part1;
	}

	public void setPart1(String part1) {
		this.part1 = part1;
	}

	public String getPart2() {
		return part2;
	}

	public void setPart2(String part2) {
		this.part2 = part2;
	}

	@Override
	public String toString() {
		return "Product [part1=" + part1 + ", part2=" + part2 + "]";
	}
} 

Director类:

public class Director {
    public Product generateProduct(ConcreteBuilder builder) {  
    	builder.makePart1("part1"); 
    	builder.makePart2("part2"); 
        return builder.build();
    }  
}

Client类:

public class Client {
	public static void main(String[] args) {
		Product product = new Director().generateProduct(new ConcreteBuilder());
		System.out.println(product);
	}
}

2.3 在源码中的应用体现:

在Android源码中最常见的Builder的运用就是AlertDialog.Builer,Notication。有兴趣的朋友可以去Android源码中查看,有了上面的结构相信很容易看出Builder的使用。

3. 单例模式

关于单例模式就运用得很普遍了,定义-一个类的实例在系统中有且只有一个实例;一般通过私有构造方法对外提供获取唯一实例的接口的方式实现。相信大多数朋友都见过或者写过,这里我们着重说一下单例的几种见的写法。

3.1 饿汉式

将类的实例声明为static并且直接赋对象,也就是在类加载的时候就已经初始化了单例的实例。由其实现方式可以看出对象是在类加载的时候就已经初始化故而可能会影响类加载的速度;但是程序在获取的时候相对就要快一些(对象已经存在直接返回);并且由于在类加载的时候就已经初始化所以这种方式是线程安全的。其写法如下:

public class Singleton {
	private static Singleton mInstanceSingleton = new Singleton();
	
	private Singleton() {
	}
	
	public static Singleton getInstance() {
		return mInstanceSingleton;
	}
}

3.2 懒汉式(线程不安全)

这种方式与饿汉式声明方式类似,只是对象的初始化不是在类加载的时候进行而是在系统第一次调用接口获取单例对象的时候初始化,这样原则上节约了内存(若不需要则不会去初始化)和此类的加载速度;这种方式由于在第一次调用的时候会初始化对象会稍微慢点(基本上忽略不计),但有一点此方式由于对象的生成在对外接口中可能会造成对象不一至,所以此种写法在线程安全的角度来说是不安全的,我们在运用的时候要特别注意。其写法如下:
public class Singleton2 {
	private static Singleton2 mInstanceSingleton = null;
	
	private Singleton2() {
	}
	
	public static Singleton2 getInstance() {
		if(mInstanceSingleton == null) {
			mInstanceSingleton = new Singleton2();
		}
		return mInstanceSingleton;
	}
}

3.3 懒汉式(线程安全)

故明思义,这种方式的出现是为了解决懒汉式线程不安全的的问题出现的,主要是通过synchronized关键字来实现线程同步的,故而性能上会差一点,但相比解决线程安全的问题是可以忽略不计的。其写法如下:

	public static synchronized Singleton3 getInstance() {
		if(mInstanceSingleton == null) {
			mInstanceSingleton = new Singleton3();
		}
		return mInstanceSingleton;
	}

或者

	public static Singleton3 getInstance2() {
		synchronized (Singleton3.class) {
		if(mInstanceSingleton == null) {
				mInstanceSingleton = new Singleton3();
			}
		}
		return mInstanceSingleton;
	}

3.4 双重检查式(Double-checked locking)

这种方式是对懒汉式(线程安全)的进化个人觉得,进行两次Null判断,第一次避免了不必要的同步操作,第二次是为Null的时候才创建实例对象。其避免了多余的线程同步操作当然这种方式也是线程安全的,其写法如下:

public class Singleton4 {
	private static Singleton4 mInstanceSingleton = null;
	
	private Singleton4() {
	}
	
	public static synchronized Singleton4 getInstance() {
		if(mInstanceSingleton == null) {
			mInstanceSingleton = new Singleton4();
		}
		return mInstanceSingleton;
	}
	
	public static Singleton4 getInstance2() {
		if(mInstanceSingleton == null) {
			synchronized (Singleton4.class) {
				if(mInstanceSingleton == null){
					mInstanceSingleton = new Singleton4();
				}
			}
		}
		return mInstanceSingleton;
	}
}

3.5 静态内部类

我们都知道加载一个类时其内部类不会同时被加载,当且仅当某个静态成员(静态成员变量,构造方法,静态方法)被调用时才去加载。这种方式我们以一个静态内部类的方式保存单例对象,如前所说当类加载时这个静态内部类不会被加载,当系统调用getInstance方法时才会去加载这个内部类进而初始化单例对象,这样既能保证对象的唯一性而且也是线程安全的,其写法如下:
public class Singleton5 {
	private Singleton5() {
	}
	public static Singleton5 getInstance() {
        return SingletonHolder.mInstance;
    }
	private static class SingletonHolder {
        private static final Singleton5 mInstance = new Singleton5();
    }
}

3.6 容器式

帮明思义,这种方式是通过容器(Map,List等)来管理单例对象,使用时根据key获取对应的实例,这种方式可以管理多种类型的单例,并且在使用时可以通过统一的接口进行获取操作,降低了用户的使用成本,屏蔽了内部的实现细节,降低了耦合度,感觉上跟线程池差不多,其写法如下:

public class Singleton6 {
	public static Map<String, Object> maps = new HashMap<String, Object>();
    public static void registerService(String key,Object instance){
        if(!maps.containsKey(key)){
        	maps.put(key, instance);
        }
    }
    public static Object getService(String key){
        return maps.get(key);
    }
}
除此之外还有枚举写法等在实际开发过程中用得比较少的方式这就不一一罗列了,以上说了比较常见的几种单例模式的写法当然各有各的好处和缺点,我们在使用的时候需要根据实际情况来衡量具体使用哪种方式,就我自己的经历来看用得比较多的为懒汉式线程安逸,其次是静态内部类,然后是饿汉式。

4. 原型模式

原型模式就是利用拷贝原型对象创建新的实例,在创建过程中不会修改原型对象的属性,即在内存中重新创建了一个新的对象并用新的引用指向这个对象。它也是为了解决复杂对象的创建而出现的。

4.1 UML类图


从UML类图中可以看出其实原型模式相对比较简单,存在以下几种角色:

抽象原型(Prototype)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体原型类所需的接口,在。面向对象编程中通常以接口或者抽象类的形式存在。

抽象产品(IProduct) 角色:面向对象的写法,抽象产品和属性和动作。

具体原型产品(PrototypeProduct)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。

原型管理器(Prototype Manager)角色:创建具体原型类的对象,并记录或者使用每一个被创建的对象。

客户(Client)角色:客户端类向原型管理器提出创建对象的请求。

4.2 代码示例

Prototype:

public abstract class Prototype {
	public abstract Prototype clone();
}

IProduct:

public abstract class IProduct extends Prototype {
	public int number;
	public String name;
	
	public int getNumber() {
		return number;
	}
	
	public void setNumber(int number) {
		this.number = number;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
}

ProtypeProduct1:

public class ProtypeProduct1 extends IProduct{
	@Override
	public Prototype clone() {
		ProtypeProduct1 protypeProduct1 = new ProtypeProduct1();
		protypeProduct1.setNumber(this.getNumber());
		return protypeProduct1;
	}
}

ProtypeProduct2

public class ProtypeProduct2 extends IProduct{
	@Override
	public Prototype clone() {
		ProtypeProduct2 protypeProduct2 = new ProtypeProduct2();
		protypeProduct2.setNumber(this.getNumber());
		return protypeProduct2;
	}
}

PrototypeManager:

public class PrototypeManager {
	public void managerProtoType(IProduct product) {
		int number = product.getNumber();
		while(number > 0) {
			System.out.println("oldProduct:" + product.hashCode());
			IProduct iProduct= (IProduct) product.clone();
			iProduct.setNumber(number >= 1000 ? 1000 : number);
            System.out.println("newProduct" + iProduct.hashCode() + " number:" + iProduct.getNumber());
            number -= 1000;
		}
	}
}

Client:

public class Client {
	public static void main(String[] args) {
		IProduct product = new ProtypeProduct1();
		product.setNumber(4500);
		product.setName("随机");
		PrototypeManager mPrototypeManager = new PrototypeManager();
		mPrototypeManager.managerProtoType(product);
	}
}

5. 最后

内容相对简单,只当自己给自己做个笔记。


猜你喜欢

转载自blog.csdn.net/rayht/article/details/79438242