浅谈应用工厂模式和单例在Android中实现业务隔离

Android中写应用,一样需要考虑到降低耦合性的问题,还有一些其他问题,比如App的增量式更新,业务变更的便捷实现等等,都会有工厂模式和单例的身影。

工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。

这里就用一个小例子来说明。

假设我们现在要写一个登陆的业务功能,按照工厂模式的思路,我们不会直接去写一个登陆的类,然后将它new出来去调用login的登陆方法,而是会先写一个接口,接口里有一个方法名login,然后写一个接口的实现类,实现login方法,然后再去将其new出来,这样做的好处在于,如果实现类改变了,接口不需要动,不会影响上层界面。假设我们这里的类分别是:User用户类,IUserEngine登陆业务接口类和UserEngineImpl登陆业务接口实现类。

到这里,貌似工厂模式差不多了?我们写一个TestCase,就可以直接实现登陆功能了?如下:

	public void testLogin() {
		User user = new User();
		user.setUserName("alex");
		user.setPasswd("123456");
		IUserEngine engine = new UserEngineImpl();
		engine.login(user);
	}

看似没有问题,但是其中却隐含了大问题。。

试想,如果你刚写完这个几百行的login方法,test也通过了,正在洋洋得意的时候,老大说,登陆业务要大改。。。怎么办?把刚写好的几百行代码删了重来?等你费了老大劲改完,通过,没准老大又说,恩 ,还是之前的好。。。

所以最好的办法是不动原来的代码,很多人一定想的到,那不就直接重新写一个接口实现类叫做:UserEngineImpl2不就行了?确实,保留原来的那个UserEngineImpl不动,只是不用它。看上去是比之前好一些,但是还是不满意,假如之前UserEngineImpl在几百个地方被调用,那不得一个个去改?所以还是麻烦。。。

所以这里最好以不变应万变,什么是不变的,就是那个接口IUserEngine!我们不妨将IUserEngine的名字与它对应的实现类的完整类名对应起来,存储在一个配置文件里面,每次我们都去配置文件中读取到底是要加载哪一个实现类,于是如果业务变更,需要修改实现类的时候,只需要更新一个实现类,并且改一下配置文件中的一行代码即可,实现如下:

BeanFactory:用来加载properties配置文件,并且实现获取对应的类的实例。而本身BeanFactory也只需要一个实例即可,所以采用单例模式,这里使用登记式单例:

package com.example.factorymode.util;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import com.example.factorymode.bean.User;
import com.example.factorymode.engine.IUserEngine;

public class BeanFactory {

	private static Properties properties;

	// 用于登记式单例模式存放BeanFactory唯一实例
	private static Map<String, BeanFactory> map = new HashMap<String, BeanFactory>();

	private static String beanFactoryName = BeanFactory.class.getName();

	static {
		// 单例模式初始化
		BeanFactory bFactory = new BeanFactory();
		map.put(BeanFactory.class.getName(), bFactory);

		// 初始化配置文件加载,只需要加载一次即可
		properties = new Properties();
		try {
			properties.load(BeanFactory.class.getClassLoader()
					.getResourceAsStream("config.properties"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 单例模式 ①提供一个私有的构造函数,使得外界不能去new ②提供一个getInstance方法,给外界提供本类自己的唯一一个实例
	 *
	 * @return
	 */
	private BeanFactory() {

	}

	// 给外界提供实例,保证唯一性,这里采用登记式单例模式
	public static BeanFactory getInstance() {

		if (map.get(beanFactoryName) == null) {
			try {
				map.put(beanFactoryName,
						(BeanFactory) Class.forName(beanFactoryName)
								.newInstance());
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return map.get(beanFactoryName);
	}

	/**
	 * 加载需要是实现类
	 *
	 * @param clazz 接口的类
	 * @return
	 */
	public <T> T getImpl(Class<T> clazz) {
		String simpleName = clazz.getSimpleName();
		String implClassName = properties.getProperty(simpleName);
		try {
			return (T) Class.forName(implClassName).newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}

我们这里的properties文件放在src目录下,这里便于使用类加载器来加载。

config.properties内容:

IUserEngine=com.example.factorymode.engine.impl.UserEngineImpl

然后我们在TestCast里就可以这样来写:

	public void testLogin2(){

		User user = new User();
		user.setUserName("alex");
		user.setPasswd("123456");

		IUserEngine engine = BeanFactory.getInstance().getImpl(IUserEngine.class);

		engine.login(user);
	}

经过上述改造,遇到业务变更的时候,就可以更从容,而且也可以应用到App的增量式更新,比如只有登录业务改变的时候,更新APP的时候就只需要更新一个配置文件,和新增一个登录实现类即可让加载时加载到新增的实现类来产生对应的实例,从而节省用户的流量。

时间: 2024-08-05 11:18:47

浅谈应用工厂模式和单例在Android中实现业务隔离的相关文章

浅谈简单工厂模式和策略模式

1.简单工厂模式如图 代码: 缺点:简单工厂模式需要客户端认识两个类,Cash和CashFactory 优点:子类的实例化被工厂封装了起来,客户端看不到 2.策略模式如图 代码: public class Context{ Strategy strategy; public Context(Strategy strategy){ this.strategy = strategy; } public double getResult(double money){ return strategy.a

容器工厂(原型&amp;单例)

上一篇讲的是容器工厂的原型. 我们可以不必通过new关键之创建实例,可以直接取容器里面的实例. 我们可以发现,在对比他们的地址值的时候,他们是相同的为true. 如果我们需要的是不一样的呢.也就是有一些特殊的操作需要到的是单例地址. 下面让我们看看如何创建一个可以随意切换原型&单例的容器工厂吧. 我们在上一篇原型的容器工厂上稍微做一下改造就OK了! 添加一个描述bean的类,封装了配置文件bean的类 public class Definition { //bean的唯一标识 private S

10 浅谈 装饰器模式的理解与使用

在不改变现有类结构的情况下,为这个类添加一个新的功能,这就是装饰器模式 所属与结构型模式, 这种模式的特点是:需要创建一个装饰类来包装原有的类,并且提供额外的功能. 为了解决:平时使用继承的方式,会带入许多静态的方法,导致子类过度饱和,膨胀. 举例子:悟空拥有七十二变,不管它怎么变化,他的本质还是一只猴子,但是他又有变化后的一些本领(功能) 实现:装饰类包含原有类的实例对象,即可实现装饰器模式 开始: 定义一个形状的接口 //画图接口 public interface Shape { void

浅谈简单工厂,工厂方法,抽象工厂的使用

前言 这几天了解了工厂模式,自己也整理下思路,任何一种模式的出现都是为了让我们的程序有更好的可扩展性,工厂模式也不例外. 简单工厂 在实际的代码coding中我们在创建对象(也就是实例化一个类)的时候往往需要new class()这样来操作.举个例子: 这是项目结构 //这是一个中国人的类public class ChinesePepole { public void Show() { Console.WriteLine("I'm a {0}", this.GetType().Name

浅谈简单工厂与工厂方法

在园子混迹许久,每日看一些大神的佳作,深感受益匪浅,进而萌生了分享一些知识的想法.当然,作为一个屌丝程序员分享不了多么高大上的知识,只是把平时工作中积累的一些东西共享出来,希望大神们手下留情,不要拍的太狠.呵呵,闲言少叙,书归正传. 简单工厂和工厂方法   GOF创造了设计模式这个家族,为我们写出更面向对象的代码提供了便利.相对于这个家族几乎代代单传,工厂家族可谓是门丁兴旺,今天主要来体验下简单工厂和工厂方法.   这里要说一个题外话,简单工厂模式不属于GOF创造的23种设计模式,最多算一个临时

浅谈浏览器标准模式与怪异模式、文档类型

在网页设计制作过程中,新人往往会遇到一个问题,就是浏览器的不兼容问题.这种状况在大学学习过程中会经常遇到,但一直也没有得到很好的解决,今天有机会仔细研究了一下,这是有关浏览器标准模式与怪异模式之间的问题.标准模式(strict mode)和怪异模式(quirks mode)是浏览器解析css的两种模式.标准模式是指浏览器按W3C标准解析执行代码:怪异模式则是使用浏览器自己的方式解析执行代码,因为不同浏览器解析执行的方式不一样,所以我们称之为怪异模式. 浏览器解析时使用测是标准模式还是怪异模式,与

浅谈简单工厂,工厂方法,抽象工厂的区别和使用

工厂模式是分为三种,分别是简单工厂,工厂方法,抽象工厂.其中工厂方法和抽象工厂是GoF23种设计模式中的一种,而简单工厂则不是一种设计模式,更加可以理解的是一种编码时候预定俗称的一种习惯.那么,就在接下来三点中分别去分析理解工厂模式. 一 简单工厂:通过实例化一个工厂类,来获取对应的产品实例.我们不需要关注产品本身如何被创建的细节,只需要通过相应的工厂就可以获得相应的实例.简单工厂包括三种角色: 1.工厂:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑.工厂类的创建产品类的方法可以被外界直

单例访问Android应用程序对象

1.单例模式: 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源.如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案. 2.单例模式优势: 由于单例模式在内存中只有一个实例,减少了内存开销 单例模式可以避免对资源的多重占用. 单例模式可以在系统设置全局的访问点,优化和共享资源访问. 2.问题:需要从android应用程序中去访问全局数据 解决

单例在多线程中的使用

一次执行  dispatch_once: 对应的代码只执行一次 , 并且它是线程安全的, 系统会自动这个函数加锁,保存同一时间只有一个线程去执行任务, 实现真正意义的一次性执行 什么时候需要用到一次性执行:  单例 单例: 就是在程序运行期间,只有一个实例化对象  ---- 举例:音乐播放器的App, 同时只能播放一首歌曲. 好处: 如果不使用同一个播放管理器对象, 那就播放下一首歌曲时, 先销毁上一个对象, 再创建一个新对象 这样做就比较消耗资源. 既然同一个时刻只能播放一首歌曲 ,所以我们只