Java设计模式--工厂模式

1. 工厂模式的作用:解决接口选择的问题

2. 何时使用:当我们明确地知道不同条件下创建不同实例时。

3. 使用场景

            --java的可移植性(java--JVM(工厂)--操作系统)

            --hibernate和mybatis切换数据库

4. 注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式

 分析一下程序

package test;

public class test {
	public static void main(String[] args) {
		Apple apple = new Apple();
		apple.eat();
		//如果突然不想吃苹果,想吃香蕉就要重新实例化一个香蕉对象
		//如此一来,每次切换都要更新客户端的代码
		//能不能有一种方式,用户想吃什么就传入什么,不需要改动客户端的代码
	}
}

class Apple{
	public void eat() {
		System.out.println("吃苹果。。。");
	}
}

class Banana{
	public void eat() {
		System.out.println("吃香蕉。。。");
	}
}

5. 改进,引入工厂类

package test;

public class test {
	public static void main(String[] args) {
		Fruit fruit = Factory.getInstance(args[0]);
		fruit.eat();
	}
}

abstract class Fruit{ //模板类
	public void eat(){} ;
}

class Apple extends Fruit{
	public void eat() {
		System.out.println("吃苹果。。。");
	}
}

class Banana extends Fruit{
	public void eat() {
		System.out.println("吃香蕉。。。");
	}
}

interface Factory{  //工厂类
	public static Fruit getInstance(String fruit) {
		if("apple".equals(fruit)) {
			return new Apple();
		}else if("banana".equals(fruit)) {
			return new Banana();
		}else {
			return null;
		}
	}
}

如此一来,只要是水果工厂里面有的水果,用户只要输入水果名称就可以吃到该水果,不需要自己再去生产该水果,生产的工作交由水果工厂负责。

但是这个代码还是有一个特别麻烦的地方,那就是每当接口产生一个新的子类的时候,接口本身也必须修改,可扩展性极低。

6. 利用反射改进工厂模式

package test;

public class TestFactory {
	public static void main(String[] args) throws Exception {
		Fruit instance = Factory.getInstance("test.Apple");
		instance.eat();
	}
}

interface Fruit{
	public void eat();
}

class Apple implements Fruit{
	@Override
	public void eat() {
		System.out.println("吃苹果...");
	}
}

class Banana implements Fruit{
	@Override
	public void eat() {
		System.out.println("吃香蕉....");
	}
}

class Factory{
	public static Fruit getInstance(String fruitClass) throws Exception {
		return (Fruit)Class.forName(fruitClass).newInstance(); //一句代码搞定,以后有新的子类也不需要再修改工厂类了
	}
}

但是这样还是不够完美,因为客户端需要明确知道子类的详细名称(包.类名),并且每次切换子类都要改动客户端,改进的方法是利用配置文件,将类名写进配置文件中,切换的时候,全部代码都不需要改动,只要改动配置文件就可以了。

7.  利用配置温文件管理工程类名

import java.util.ResourceBundle;
public class TestFactory {
	public static final ResourceBundle rb = ResourceBundle.getBundle("fruit");//使用配置文件
	public static void main(String[] args) throws Exception {
		Fruit instance = Factory.getInstance(rb.getString("fruitClass"));
		instance.eat();
	}
}
interface Fruit{
	public void eat();
}

class Apple implements Fruit{
	@Override
	public void eat() {
		System.out.println("吃苹果...");
	}
}

class Banana implements Fruit{
	@Override
	public void eat() {
		System.out.println("吃香蕉....");
	}
}

class Factory{
	public static Fruit getInstance(String fruitClass) throws Exception {
		return (Fruit)Class.forName(fruitClass).newInstance(); //一句代码搞定,以后有新的子类也不需要再修改工厂类了
	}
}

上面的代码仍不完美,不完美之处在于需要用户去手工修改配置文件。所以必须想一种办法,把配置写回配置中,又可以跟程序进行有效的分离。参考servlet开发的经验,使用Annotation来实现配置。

8. 利用annotation改进工厂模式

package factory;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Factory(className = "factory.Apple")
public class TestFactory3{
	public static void main(String[] args) {
		Fruit fruit;
		try {
			fruit = getFruit();
			fruit.eat();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	private static Fruit getFruit() throws Exception {
		Class cls = TestFactory3.class;
		Factory an = cls.getAnnotation(Factory.class);//取得工厂annotation
		return  (Fruit)Class.forName(an.className()).newInstance(); //返回工厂实例
		
	}
	
}

interface Fruit{
	public void eat();
}

class Apple implements Fruit{
	@Override
	public void eat() {
		System.out.println("吃苹果...");
	}
}

class Banana implements Fruit{
	@Override
	public void eat() {
		System.out.println("吃香蕉....");
	}
}

//写自己的annotation
@Retention(RetentionPolicy.RUNTIME)
@interface Factory{
	public String className() ;
}

9. 继续优化,简化客户端annotation

package factory;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Factory(className = "Banana")
public class TestFactory3{
	public static void main(String[] args) {
		Fruit fruit;
		try {
			fruit = getFruit();
			fruit.eat();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	private static Fruit getFruit() throws Exception {
		Class cls = TestFactory3.class;
		Factory an = cls.getAnnotation(Factory.class);//取得工厂annotation
		return  (Fruit)Class.forName(Fruit.class.getPackage().getName()+"."+an.className()).newInstance(); //返回工厂实例
	}
	
}

interface Fruit{
	public void eat();
}

class Apple implements Fruit{
	@Override
	public void eat() {
		System.out.println("吃苹果...");
	}
}

class Banana implements Fruit{
	@Override
	public void eat() {
		System.out.println("吃香蕉....");
	}
}

//写自己的annotation
@Retention(RetentionPolicy.RUNTIME)
@interface Factory{
	public String className() ;
}

 

你可能感兴趣的:(设计模式,设计模式,工厂模式)