单例模式
确保某一个类只有一个实例,而且自行实例化并向整个系统提供整个实例
代码实现
public class Singleton {
//private限定初始化,保证自动初始化且只初始化一个对象
private static final Singleton singleton=new Singleton();
//私有化构造函数,防止创建多个变量
private Singleton() {
}
//提供给外部访问这个对象
public static Singleton getSingleton(){
return singleton;
}
}
//通过get方法获取同一个对象
Singleton singleton=Singleton.getSingleton();
优点
- 单例模式只在内存中创建一份对象,减少内存开支,特别适用于对象频繁创建和销毁
- 可以永久驻留内存,适用于对象产生时比较消耗资源的对象
- 避免对资源的多重占用,防止对同一个资源文件同时修改的操作
缺点
- 单例模式没有接口,拓展比较困难
- 单例模式要写完才能进行单元测试,没有接口也不能使用mock
- 单例模式与单一职责原则有冲突,单例模式考虑的是内存优化,并不是为了实现目标。
使用场景
- 要求生成唯一序列号的环境
- 项目中需要一个共享访问点或共享数据
- 创建对象需要消耗资源过多时
- 需要创建大量工具类常量的时候
拓展,一个类只产生2-3个对象(或固定多个对象):有上限的单例模式
例:一个班只有固定的三个老师,学生随机找老师送教师节礼物,构建一个只有固定三个对象的老师类
public class Teacher {
//最多产生的实例数量
private static final int MAX_TEACHER=3;
//定义一个列表去存放老师的私有属性,比如名字
private static ArrayList<String> namelist=new ArrayList<>();
//定义一个列表去存放老师的对象实例
private static ArrayList<Teacher> teacherList= new ArrayList<>();
//私有化构造方法,约束不能从外部请老师
private Teacher(){
}
private Teacher(String name){
namelist.add(name);
}
//初始化
static {
for (int i=0;i<MAX_TEACHER;i++){
teacherList.add(new Teacher("第"+i+"个老师"));
}
}
//随机获得一个老师对象
public Teacher getTeacher(){
Random random = new Random();
return teacherList.get(random.nextInt(MAX_TEACHER));
}
}
Spring中的bean默认为单例模式
工厂方法模式
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到子类
通用源码
抽象产品类,负责定义产品的共性,给具体的产品类提供模板
public abstract class Product {
//产品类的公共方法
public void method1(){
}
//抽象方法
public abstract void method2();
}
具体产品类,可以有多个
public class ConcreteProduct extends Product{
/**
* 具体产品类,只要继承了Product抽象类的都是具体产品类
* 具体产品类可以有多个
*/
@Override
public void method2() {
//业务逻辑处理
}
}
抽象工厂类,负责定义产品对象的产生
public abstract class Creator {
/**
* 创建一个产品对象,可以通过设置输入参数类型
*/
public abstract <T extends Product> T createProduct(Class<T> c) throws ClassNotFoundException, IllegalAccessException, InstantiationException;
}
工厂类
public class ConcreteCreator extends Creator{
@Override
public <T extends Product> T createProduct(Class<T> c) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Product product=null;
product= (Product) Class.forName(c.getName()).newInstance();
return (T)product;
}
}
使用的时候只要传递相应的具体产品类,就可以创建对应产品对象
优点
- 良好的封装性,调用者只需要知道具体产品类的类名就可以调用
- 上层应用屏蔽了产品类,不需要考虑产品类是如何实现的
使用场景
- 需要灵活的,可拓展的框架的时候
- 异构项目中
扩展
简单工厂模式
一个模块仅需要一个工厂类,不需要编写抽象工厂类,直接使用static构建一个工厂类
多个工厂类模式
如果具体产品类创建比较麻烦,且没有共性抽出来成为一个抽象产品类,可以使用多个创建者与具体产品类一一对应(加一层封装)
替代单例模式
在工厂类通过获得类构造器,然后设置访问权限,生成一个对象,然后提供内部访问
可以保证内存中的对象唯一
延迟初始化
一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态
在工厂类定义一个Map容器,容纳所有产生的对象,如果在Map容器中已经有的对象,则直接返回对象
若没有对象,则根据需要的类型产生一个对象放入到Map容器中
抽象工厂模式
为创建一组相关或项目依赖的对象提供一个接口,而且无需制定他们的具体类
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
代码实现
/**
* 抽象产品类
* 定义产品公用的方法
* 定义产品相同但不同实现的方法
*/
public abstract class AbstractProductA {
public void shareMethod(){
}
public abstract void doSomething();
}
/**
* 具体产品类A,属于A类的产品
*/
public class ProductA extends AbstractProductA {
@Override
public void doSomething() {
System.out.println("产品A的实现方法");
}
}
/**
* 具体产品类B,属于A类的产品
*/
public class ProductB extends AbstractProductA {
@Override
public void doSomething() {
System.out.println("产品B的实现方法");
}
}
/**
* 抽象工厂类,负责定义每个工厂要实现的功能
* 定义了产品家族的创建
* 有多少个产品族就有多少个创建方法
*/
public abstract class AbstractCreator {
//创建A产品家族
public abstract AbstractProductA createAbstractProductA();
}
/**
* 产品等级1的实现类
*/
public class Creator1 extends AbstractCreator{
@Override
public AbstractProductA createAbstractProductA() {
return new ProductA();
}
}
/**
* 场景类
*/
public class Client {
public static void main(String[] args) {
//创建产品类1的工厂
AbstractCreator creator1 = new Creator1();
//创建A1对象
AbstractProductA abstractProductA = creator1.createAbstractProductA();
//A1对象的方法
abstractProductA.doSomething();
}
}
优点
- 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
- 使用的时候,没有任何一个方法和实现类有关系,知道对应的工厂方法creator1.createAbstractProductA();就可以创建出产品对象
- 每个产品的实现类封装在底部,创建对象不需要考虑具体的对象实现
- 高层模块只需要关注接口(抽象模块)
- 产品族内部的约束会限制在底层模块中
缺点
- 产品族扩展困难,需要改变抽象工厂类,增加一个产品族的扩展方法,然后要修改产品等级对应的实现类
注意事项
- 产品族扩展困难,但产品等级拓展容易拓展,创建一个新的工厂类去管理新的产品等级,一个工厂加相应的等级类,不需要修改原有的代码,代码侵染性讲到了最低
模板方法模式
定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
代码实现
public abstract class AbstractClass {
//基本方法
protected abstract void dosomething();
//基本方法2
protected abstract void dosomething2();
//模板方法
public void templatemethod(){
this.dosomething();
this.dosomething2();
}
}
通过抽象类定义共同的模板方法,给子类调用
优点
- 封装不变部分,扩展可变部分
- 提取公共部分代码,便于维护
- 行为由父类控制,子类实现,子类可以通过扩展的方式增加相应的功能
缺点
抽象类实现了一部分方法,子类执行的结果影响了父类的结果