单例、多例模式
假设,老张开车去东北
public class Car {
public void run(){
System.out.println("冒着烟奔跑中car.........");
}
}
public class Test {
public static void main(String[] args) {
//如果把new交给司机,那么司机想new多少car就能有多少。
Car c=new Car();
c.run();
}
}
想要控制只给老张一辆车,不让他随便new出来,可以把Car的构造函数设为private,Car自主生产一个实例,不再依赖于new,封装一个方法,让Car定义一个方法返回唯一实例。
单例模式
public class Car {
private static Car car=new Car(); //实例
private Car(){ } //构造函数私有
//单例模式的getInstance方法==静态工厂方法
public static Car getInstance(){
return car;
}
public void run(){
System.out.println("冒着烟奔跑中car.........");
}
}
测试:
因为Car的getInstance()方法返回static变量,是同一个实例,所以c1和c2是同一个对象。
public class Test {
public static void main(String[] args) {
Car c1=Car.getInstance();
Car c2=Car.getInstance();
if(c1==c2){
System.out.print("same car");
}
}
}
如果需要在Car中产生多个实例,不只是一个实例,可以用多例模式。
比如JDBC的连接池,从池中选择一条连接使用,使用后回收到池中,Connection就是多例
多例模式
在Car中定义List<Car>
成员变量
private static List<Car> cars=new ArrayList<Car>();
再把cars初始化,当需要使用的时候,就从cars中选择一个使用。
工厂模式
new产生实例,如果想对对象的生产过程也能够进行定制,有好多可扩展性,且能封装生产过程,使用工厂模式
1、简单工厂模式
//Moveable接口用于实现run
public class Car implements Moveable{
@Override
public void run() {
System.out.print("开汽车\n");
}
}
//Moveable接口用于实现run
public class Plane implements Moveable {
@Override
public void run() {
System.out.print("开飞机\n");
}
}
工厂
public class CarFactory {
public Car createCar(){
return new Car();
}
}
public class PlaneFactory {
public Plane createPlane(){
return new Plane();
}
}
public class Test {
public static void main(String[] args) {
PlaneFactory planeFactory=new PlaneFactory();
Plane p=planeFactory.createPlane();//从工厂获取
p.run();
}
}
简单工厂模式的工厂可扩展性不好,如果想要替换工厂,则换掉的工厂方法也得改,可扩展性不好
2、抽象工厂模式
产生交通工具的抽象工厂
public abstract class VehicleFactory {
abstract Moveable create();
}
继承自抽象工厂类的具体工厂(子工厂)
public class CarFactory extends VehicleFactory{
@Override
Moveable create() {
return new Car();
}
}
public class PlaneFactory extends VehicleFactory{
@Override
Moveable create() {
return new Plane();
}
}
public class Test {
public static void main(String[] args) {
VehicleFactory factory=new PlaneFactory();
Plane p=(Plane) factory.create();//多态,会隐藏具体实现方法
p.run();
factory=new CarFactory();
Car c=(Car) factory.create();//多态,会隐藏具体实现方法
c.run();
}
}
不仅可以控制对象,还可以控制对象的生产过程。
需要修改的只有VehicleFactory factory=new PlaneFactory();
,需要生产什么对象,就new出相应的工厂,如果有配置文件,连这个都不用修改
体会:产生对象的方法,就是工厂方法,不一定局限于是在哪个位置,是哪个范畴,学习到最后要灵活运用,手中无剑心中有剑
getInstance和Factory在jdk中常用,还有abstractFactory也非常常用
3、配置文件
对于普通工厂来说,产生产品系列时,会产生工厂泛滥的问题,对于抽象工厂来说,也有一个问题:比如抽象工厂类,当它需要在抽象类中添加或者删去一个方法(即改变产品时),就需要改动所有继承自该厂的所有子类的方法,改动的地方太多
spring提供了一种方案:
1、spring提供的是bean工厂(BeanFactory)
2、原先通过new方式得到的实例Bean对象,现在通过配置文件的配置来配置实例
模拟spring
1、配置文件spring.properties
VehicleType=com.HL.spring.Train // 键值对
2、通过java的Properties、反射来获取实例对象
package com.HL.spring;
import java.io.IOException;
import java.util.Properties;
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
//用来读配置文件的
Properties pros=new Properties();
//Test.class.getClassLoader():拿到装载类对象的class装载器,getResourceAsStream:把文件当成流
pros.load(Test.class.getClassLoader().getResourceAsStream("com/HL/spring/spring.properties"));
//获取key为VehicleType的值
String vehicleTypeName=pros.getProperty("VehicleType");
System.out.println(vehicleTypeName);
//运用java的反射机制,通过字符串得到实例
Object o=Class.forName(vehicleTypeName).newInstance();
Moveable m=(Moveable)o;
m.run();
}
}
4、Spring
Spring中的运用:使用application.xml作为全局配置文件
application.xml中的配置信息
<Bean id="v" class="com.HL.spring.Car" />
加载配置文件,用ClassPathXmlApplication
BeanFactory f=new ClassPathXmlApplicationContext("application.xml");//加载配置文件中配置的Bean类
java解析XML文件,有多种方法,比如JDOM、SAX等,可以搜索一下JDOM/XPATH编程指南.
spring中加载完xml配置文件之后,会把配置文件中声明的Bean放在List中,然后放进Map中,即Bean容器(IOC),提供给应用程序(程序通过getBean根据id得到Bean),即AOP
Object o=f.getBean("v");//根据id获取相应ID的Bean实例
Moveable m=(Moveable)o;
m.run();
这就是Bean容器,即IOC。