shiro是一个简单易用,功能强大的Java安全框架,学习其源码设计思想对咱们的编码水平的提升大有裨益。如今,就从源码角度带你们学习一下shiro里面的工厂方法模式。 这里的前提是读者有过使用shiro的基础,没有也行,关键理解思想就能够了。html
首先,咱们先从一个简单的例子提及。咱们在使用ini文件来做为用户角色权限配置的时候,咱们获取SecurityManager的方法是:java
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:demo01_getstarted.ini");
SecurityManager securityManager = factory.getInstance();
复制代码
上面两行代码看似简单,其实框架底层就使用了工厂方法模式。
关于上面的例子就很少讲了。这里是侧重分析工厂方法设计模式。设计模式
在工厂方法模式中,咱们对模式角色划分为四种:
一、抽象产品(产品接口):好比上面shiro实例中的SecurityManager
二、具体产品:好比实现了SecurityManager的类
三、抽象工厂(工厂接口):好比上面shiro实例中的Factory、AbstractFactory
四、具体工厂:好比上面shiro实例中的IniSecurityManagerFactory
安全
咱们先来看看shiro里面工厂方法模式实现的源码:
angular2
1、顶级工厂抽象接口Factory,全部抽象工厂类都继承此接口
框架
public interface Factory<T> {
T getInstance();
}
复制代码
2、抽象工厂类,这个抽象工厂类负责获取工厂实例,具体建立过程由其子类来实现
ide
public abstract class AbstractFactory<T> implements Factory<T> {
private boolean singleton;
private T singletonInstance;
public AbstractFactory() {
this.singleton = true;
}
public boolean isSingleton() {
return singleton;
}
public void setSingleton(boolean singleton) {
this.singleton = singleton;
}
// 获取工厂实例,能够以单例形式获取,也能够每一次获取都建立一个实例
public T getInstance() {
T instance;
if (isSingleton()) {
if (this.singletonInstance == null) {
this.singletonInstance = createInstance();
}
instance = this.singletonInstance;
} else {
instance = createInstance();
}
if (instance == null) {
String msg = "Factory 'createInstance' implementation returned a null object.";
throw new IllegalStateException(msg);
}
return instance;
}
protected abstract T createInstance();
}
复制代码
上面两个工厂类抽象了最基本的工厂接口--建立工厂、获取工厂。若是咱们须要对工厂类进行扩展的话,只须要继承AbstractFactory来实现便可,很是方便。如今看一下AbstractFactory的一个子类。
IniFactorySupport是一个特定的抽象工厂类,是根据ini文件来建立工厂实例的工厂抽象类。咱们不须要细究IniFactorySupport代码干了什么。只须要明白,它是对根据ini文件建立工厂作了一些逻辑处理就行了。
咱们能够看到,继承AbstractFactory,咱们能够随便扩展定制咱们工厂类的行为。源码分析
public abstract class IniFactorySupport<T> extends AbstractFactory<T> {
public static final String DEFAULT_INI_RESOURCE_PATH = "classpath:shiro.ini";
private static transient final Logger log = LoggerFactory.getLogger(IniFactorySupport.class);
private Ini ini;
private Map<String, ?> defaultBeans;
protected IniFactorySupport() {
}
protected IniFactorySupport(Ini ini) {
this.ini = ini;
}
public Ini getIni() {
return ini;
}
public void setIni(Ini ini) {
this.ini = ini;
}
protected Map<String, ?> getDefaults() {
return defaultBeans;
}
public void setDefaults(Map<String, ?> defaultBeans) {
this.defaultBeans = defaultBeans;
}
public static Ini loadDefaultClassPathIni() {
Ini ini = null;
if (ResourceUtils.resourceExists(DEFAULT_INI_RESOURCE_PATH)) {
log.debug("Found shiro.ini at the root of the classpath.");
ini = new Ini();
ini.loadFromPath(DEFAULT_INI_RESOURCE_PATH);
if (CollectionUtils.isEmpty(ini)) {
log.warn("shiro.ini found at the root of the classpath, but it did not contain any data.");
}
}
return ini;
}
protected Ini resolveIni() {
Ini ini = getIni();
if (CollectionUtils.isEmpty(ini)) {
log.debug("Null or empty Ini instance. Falling back to the default {} file.", DEFAULT_INI_RESOURCE_PATH);
ini = loadDefaultClassPathIni();
}
return ini;
}
public T createInstance() {
Ini ini = resolveIni();
T instance;
if (CollectionUtils.isEmpty(ini)) {
log.debug("No populated Ini available. Creating a default instance.");
instance = createDefaultInstance();
if (instance == null) {
String msg = getClass().getName() + " implementation did not return a default instance in " +
"the event of a null/empty Ini configuration. This is required to support the " +
"Factory interface. Please check your implementation.";
throw new IllegalStateException(msg);
}
} else {
log.debug("Creating instance from Ini [" + ini + "]");
instance = createInstance(ini);
if (instance == null) {
String msg = getClass().getName() + " implementation did not return a constructed instance from " +
"the createInstance(Ini) method implementation.";
throw new IllegalStateException(msg);
}
}
return instance;
}
protected abstract T createInstance(Ini ini);
protected abstract T createDefaultInstance();
}
复制代码
经过看类关系图,IniSecurityManagerFactory继承IniFactorySupport,在IniFactorySupport基础上面进一步封装建立工厂过程。
IniSecurityManagerFactory的源码就不贴出来了,明白设计思想就能够了。
经过源码分析,咱们能够看到,首先抽象出最基本的工厂接口,具体的工厂类由其子类去实现。一个具体工厂类对应这一类产品。当须要新增产品类的时候,咱们只须要新加工厂类,而且新增对应的产品类便可,不须要修改原有工厂类代码,符合了设计模式中的开闭原则、单一职责原则。学习
1、建立工厂接口:IFactory IFactory.javaui
/**
* 泛型表明的是产品类型
*
* @author wunanliang
* @date 2018/1/8
* @since 1.0.0
*/
public interface IFactory<T> {
/**
* 获取产品
*
* @return 产品实例
*/
T getInstance();
}
复制代码
进一步抽象工厂接口 AbstractFactory.java
/**
* @author wunanliang
* @date 2018/1/8
* @since 1.0.0
*/
public abstract class AbstractFactory<T> implements IFactory<T> {
/**
* 建立产品,具体建立过程由其子类实现
*
* @return 建立的产品实例
*/
protected abstract T createInstance();
@Override
public T getInstance() {
return createInstance();
}
}
复制代码
2、建立产品接口 IProduct.java
/**
* @author wunanliang
* @date 2018/1/8
* @since 1.0.0
*/
public interface IProduct {
}
复制代码
进一步分类产品,建立一类产品接口 Car.java
/**
* @author wunanliang
* @date 2018/1/8
* @since 1.0.0
*/
public abstract class Car implements IProduct {
/**
* 建立汽车产品
*
* @return 建立的汽车产品
*/
protected abstract Car createCar();
/**
* 驾驶汽车
*/
public abstract void drive();
}
复制代码
具体产品类 Taxi.java
/**
* @author wunanliang
* @date 2018/1/8
* @since 1.0.0
*/
public class Taxi extends Car {
private Taxi taxi;
@Override
protected Car createCar() {
this.taxi = new Taxi();
return this.taxi;
}
@Override
public void drive() {
System.out.println("我是接送客的车");
}
}
复制代码
3、建立具体产品的工厂类 TaxtFactory.java
/**
* @author wunanliang
* @date 2018/1/8
* @since 1.0.0
*/
public class TaxiFactory extends AbstractFactory<Car> {
@Override
protected Car createInstance() {
return new Taxi();
}
}
复制代码
4、客户端代码 Client.java
/**
* @author wunanliang
* @date 2018/1/8
* @since 1.0.0
*/
public class Clent {
public static void main(String[] args) {
IFactory<Car> factory = new TaxiFactory();
Car taxi = factory.getInstance();
taxi.drive();
}
}
复制代码
经过例子,咱们知道,在工厂方法模式中,有一个顶级的产品接口,对产品做出作基本的抽象,而后产品下面还有不一样产品的分类,在同一类产品中又有不一样的具体产品,好比car类产品下面又会有多种汽车产品。每个具体的产品都有对应一个具体的工厂类。 若是想再新加一个新的产品,不管是car类产品,仍是非car类产品,咱们均可以经过新加工厂类和产品类来实现,好比新增一个船类产品
Ship.java
/**
* @author wunanliang
* @date 2018/1/8
* @since 1.0.0
*/
public abstract class Ship implements IProduct {
/**
* 造船
*
* @return
*/
protected abstract IProduct createShip();
public abstract void doSomething();
}
复制代码
建立渔船 FishShip.java
/**
* 渔船
*
* @author wunanliang
* @date 2018/1/8
* @since 1.0.0
*/
public class FishShip extends Ship {
private FishShip ship;
@Override
public IProduct createShip() {
this.ship = new FishShip();
return this.ship;
}
@Override
public void doSomething() {
System.out.println("我在打鱼呀");
}
}
复制代码
建立渔船工厂类 FishShipFactory.java
/**
* @author wunanliang
* @date 2018/1/8
* @since 1.0.0
*/
public class FishShipFactory extends AbstractFactory<Ship> {
@Override
protected Ship createInstance() {
return new FishShip();
}
复制代码
添加一个产品,咱们就得添加产品类和工厂类。对于系统的扩展来讲,工厂方法模式有优点,可是会增长系统的复杂度以及类的数量。
对于设计模式,你们重点是理解这样设计的原理与优缺点,不要机械的背诵条条框框。实际咱们在开发真实系统时,会糅合多种设计模式在一块儿。只有咱们对设计模式有本质性的认识和掌握,才是真正掌握了设计模式。