深刻理解模板模式及实际应用

        原来写了一个博客,记一次Spring环境使用模板模式。用了以后美滋滋。可是经过这几天的压力测试。发现,都怪本身太年少,太懵懂,太无知。java

如今好好梳理下模板模式的使用姿式。算法

模板模式基本使用场景:

        模板方法模式是经过父类创建框架,子类在重写了父类部分方法以后,在调用从父类继承的方法,产生不一样的效果,经过修改子类,影响父类行为的结果,模板方法在一些开源框架中应用很是多,它提供了一个抽象类,而后开源框架写了一堆子类,若是须要扩展功能,能够继承此抽象类,而后覆写protected基本方法,而后在调用一个相似TemplateMethod()的模板方法,完成扩展开发。spring

模板模式优势:

        模板方法模式是比较简单的一种设计模式,可是它倒是代码复用的一项基本的技术,在类库中尤为重要,它遵循“抽象类应当拥有尽量多的行为,应当拥有尽量少的数据”的重构原则。做为模板的方法要定义在父类中,在方法的定义中使用到抽象方法,而只看父类的抽象方法是根本不知道怎样处理的,实际作具体处理的是子类,在子类中实现具体功能,所以不一样的子类执行将会得出不一样的实现结果,可是处理流程仍是按照父类定制的方式。这就是模板方法的要义所在,制定算法骨架,让子类具体实现。 其实也是抽象类的使用优势。编程

Sping环境使用:

        spring环境中不免的注入属性,而后进行逻辑处理。这时注入就是问题。直接是不能给抽象父类注入的。抽象类不能被实例化。因此就有了子类注入后为父类设置。super.name = this.name;这种反人类的注入方式。最后参考了不少方式优化了仅在抽象父类中使用set方法注入全部公用属性。这里不使用抽象类的构造函数注入也是为了减小子类的重复代码。设计模式

JDK 1.8 模板模式和接口默认方法:

        jdk1.8 很大的变化就是函数式编程,和接口默认方法。接口默认方法在《JAVA 8 IN ACTION》 中是对API接口维护者的重大感受,不用由于接口的改变,而对实现类改变。而后就是默认方法的最接口方法的组合和选择。通过我实际使用发现,在注入属性时仍是有不少不便的地方。app

这是接口默认方法的方式:https://yq.aliyun.com/articles/18211框架

我使用了Lambda函数接口实现模板模式更加灵活;函数式编程

传统模板模式:函数

/**
  *	在线银行
  */
abstract class OnlineBanking{
   /**
	* 模板方法
	*/
	public processCustomer(int id){
		Customer c = Datebase.getCustomerWithID(id);
		makeCustomerHappy(c);
	}

   /**
	* 让上帝爽
	*/
	abstract void makeCustomerHappy(Customer c );
}

Lambda版本:测试

/**
  *	在线银行
  */
@Service
public class OnlineBanking{
   /**
	* 模板方法
	*/
	public processCustomer(int id,Consumer<Customer> makeCustomerHappy){
		Customer c = Datebase.getCustomerWithID(id);
		makeCustomerHappy.accept(c);
	}
}

// 使用方式
public class Test{
	@Autowried
	OnlineBanking onlineBanking;

	public void test{
	onlineBanking.processCustomer(123,(Consumer c) -> {
		// 作一些羞羞的事
	})
	}
}

至此,完毕。

如下几个知识点是本次使用中反复用到的:

类加载顺序:

1、过程
  Person p = new Person();
  1,JVM会去读取指定路径下的Person.class文件,并加载进内存,
    并会先加载Person的父类(若是有直接父类的状况下)
  2,在堆内存中开辟空间,分配地址。
  3,并在对象空间中,对对象中的属性进行默认初始化
  4,调用对应的构造函数,进行初始化
  5,在构造函数中,第一行会先调用父类中的构造函数进行初始化。
  6,父类初始化完毕后,再对子类的属性,进行显示初始化。
  7,指定构造函数的特定初始化
  8,初始化完毕后,将堆内存中的地址值赋给引用变量。
  即:过程为:
   子类属性默认初始化==》父类构造函数初始化==》子类属性显示初始化!!!
2、特色:
  在子类构造对象时,发现,访问子类构造函数时,父类也运行了。
    一】具体:
      在子类的构造函数中第一行有一个默认的隐式语句。 super();
      可是,当本身在子类构造函数中写了一个super的构造语句,则就不会自动调用了。
    注意:当父类中构造函数为Fu(int x)时,
       子类中则必须用super(6);不然报错!
    子类的实例化过程当中:
     子类中全部的构造函数默认都会访问父类中的空参数构造函数。
    3、【重点】为何子类实例化的时候要访问父类中的构造函数?
     1》子类继承了父类,获取到了父类中的内容(属性),因此在使用父类内容以前
       要先看父类是如何对本身的内容进行初始化的。
        因此子类在构造对象时,就必须访问父类中的构造函数,所以要在子类的构造函数中加入super语句。
     2》若是父类中没有定义空构造函数,那么子类的构造函数必须用super明确调用父类中对应的构造函数
     3》子类构造函数中若是使用this调用了本类构造函数时,则调用this的这个构造函数中super便没有了,
        由于super和this都只能定义在第一行。
        可是能够保证的是,子类中确定会有其它的构造函数访问父类的构造函数。
     注:super语句必需要定义在子类构造函数的第一行。由于父类的初始化动做要先完成。
     注:java全部的类都是Objiect的子类。

java中 抽象类构造方法的理解

抽象类能够有构造方法,只是不能直接建立抽象类的实例对象而已。

在继承了抽象类的子类中经过super(参数列表)调用抽象类中的构造方法

示例代码以下:

运行结果:

 

抽象类虽然不能本身实例化对象,可是在子类新建对象调用子类的构造方法时会先调用抽象类的无参构造方法,这样一来,就能够给给抽象类的参数赋值了。

相关文章
相关标签/搜索