一Spring框架基础--2设计模式
1.3 spring用到的设计模式
1.3.1 责任链模式
有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求。但是发出者并不清楚到底最终那个对象会处理该请求,所以,责任链模式可以实现,在隐瞒客户端的情况下,对系统进行动态的调整。
public abstract class AbstractHandler {
private Handler handler;
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
}
Abstracthandler类提供了get和set方法,方便MyHandle类设置和修改引用对象,MyHandle类是核心,实例化后生成一系列相互持有的对象,构成一条链
public class MyHandler extends AbstractHandler implements Handler {
private String name;
public MyHandler(String name) {
this.name = name;
}
@Override
public void operator() {
//调用链之前,业务操作
System.out.println(name+"before deal!");
if(getHandler()!=null){
getHandler().operator();
}
//调用链之后,业务操作
System.out.println(name+"after deal!");
}
}
public class Test {
public static void main(String[] args) {
MyHandler h1 = new MyHandler("h1");
MyHandler h2 = new MyHandler("h2");
MyHandler h3 = new MyHandler("h3");
h1.setHandler(h2);
h2.setHandler(h3);
h1.operator();
}
}
此处强调一点就是,链接上的请求可以是一条链,可以是一个树,还可以是一个环,模式本身不约束这个,需要我们自己去实现,同时,在一个时刻,命令只允许由一个对象传给另一个对象,而不允许传给多个对象。
1.3.2 代理模式
interceptorHandler
详细见[1.4代理模式](##1.4 代理模式)
1.3.3 工厂模式
(1)普通工厂模式
建立一个工厂,负责对实现了同一个接口的一些类,进行实例的创建。
//创建工厂类
public class SendFactory {
public Sender produce(String type) {
if ("mail".equals(type)) {
return new MailSender();
} else if ("sms".equals(type)) {
return new SmsSender();
} else {
System.out.println("请输入正确的类型!");
return null;
}
}
}
//使用
public class FactoryTest {
public static void main(String[] args) {
SendFactory factory = new SendFactory();
Sender sender = factory.produce("sms");
sender.Send();
}
}
缺点:利用factory创建需要传入字符串,如果出错不能创建。
(2)多个工厂方法模式
对普通的factory传入字符串的改进,创建多个方法实现不同对象的创建
public class SendFactory {
public Sender produceMail(){
return new MailSender();
}
public Sender produceSms(){
return new SmsSender();
}
}
(3)静态工厂方法模式
将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
public class SendFactory {
//方法为static,可直接调用
public static Sender produceMail(){
return new MailSender();
}
public static Sender produceSms(){
return new SmsSender();
}
}
(4)抽象工厂模式
前面三种工厂模式一个问题,类的创建依赖factory,当需要拓展程序,需要对factory修改,违背了设计模式的闭包原则。
考虑用抽象工厂模式,创建多个相应的工厂类,一旦需要增加新的功能,就相应的创建新的factory。
public class SendMailFactory implements Provider {
@Override
public Sender produce(){
return new MailSender();
}
}
//工厂类生产的抽象接口
public interface Provider {
public Sender produce();
}
public class Test {
public static void main(String[] args) {
Provider provider = new SendMailFactory();
Sender sender = provider.produce();
sender.Send();
}
}
(5)spring中的工厂模式
工厂模式和spring IOC设计思想契合:某一接口的具体实现类的选择控制权从调用类中移除,转而交给第三方决定,即借由Spring的Bean配置来实现控制。
spring就是封装工程中大量重复代码的工具。spirng重要的组件是IOC,而IOC重要部分就是应用了工厂模式的代码。工厂模式依赖于Java反射机制。
反射机制是程序运行过程中,任何对象可以获取它的类和方法、属性。
//1.加载驱动程序
Class.forName("com.mysql.jdbc.Driver");
//2.获得数据库链接
Connection conn=DriverManager.getConnection(URL, USER, PASSWORD);
Class.forName()方法就是在程序运行的过程中,动态的将Driver这个类加加载到JVM(Java虚拟机)中并初始化,然后我们就能够直接调用这个类及其方法。实际上最简单的工厂模式就是用的这个方法,在JVM运行期直接通过forName方法创建某个类
spring工厂模式,不使用new创建对象,使用共同interface接收实现类对象。因此使用时候,直接调用接口的方法,只需要改变实现此接口的实现类,就可以完成对象的创建和软件的迭代。
import java.util.ResourceBundle;
/**
* 使用此工厂类创建bean实例
*/
public class BeanFactory {
//加载配置文件(static块来静态加载)
private static ResourceBundle bundle;
static {
bundle = ResourceBundle.getBundle("instance");
}
//根据指定的key,读取配置文件的全路径,创建对象
public static <T>T getInstance(String key,Class<T> clazz){
String className = bundle.getString(key);
//反射创建实例对象
try {
return (T)Class.forName(className).newInstance();
}catch (Exception e){
throw new RuntimeException();
}
}
}
ResourceBundle这个类是用来读取classpath中文件,这个文件需要放在resources文件夹或java包的根路径下,文件名必须是*.properties这个配置文件类型。这样读取到的文件流就形成了键值对的存储形式。配置文件的示例如下(使用键值对的方式配置):
#service instance
foodTypeService=service.impl.FoodTypeService
dinnerTableService=service.impl.DinnerTableService
注意,配置文件中配置的需是接口的实现类,因为在工厂创建Bean的时候我们是使用接口来接收实现类的,这样才能够实现解耦合。
调用时候:
protected IDinnerTableService dinnerTableService = BeanFactory.getInstance("dinnerTableService",IDinnerTableService.class);
beanfactory与applicationContext的关系,[详见2.2](##2.2 ApplicationContext与BeanFactory)
1.3.4 观察者模式
详见[1.5](##1.5 事件机制event-listener—观察者模式)
spring中applicationListener的使用:
ApplicationListener是Spring事件机制的一部分,与抽象类ApplicationEvent类配合来完成ApplicationContext的事件机制。
如果容器中存在ApplicationListener的Bean,当ApplicationContext调用publishEvent方法时,对应的Bean会被触发。这一过程是典型的观察者模式的实现
1.5.1 spring中的事件处理
Spring 的核心是 ApplicationContext,它负责管理 beans 的完整生命周期。当加载 beans 时,ApplicationContext 发布某些类型的事件。例如,当上下文启动时,ContextStartedEvent 发布,当上下文停止时,ContextStoppedEvent 发布。
(通过 ApplicationEvent 类和 ApplicationListener 接口来提供在 ApplicationContext 中处理事件。如果一个 bean 实现 ApplicationListener,那么每次 ApplicationEvent 被发布到 ApplicationContext 上,那个 bean 会被通知)
Spring提供的标准事件
(这些事件,都是对applicationcontext进行相关操作时,相对应的事件)
注意:spring的事件处理是单线程,当一个线程发布,直至所有接收者得到该消息,否则该进程被阻塞,流程不会继续。
(1)监听上下文context事件
通过 ApplicationEvent 类和 ApplicationListener 接口来提供在 ApplicationContext 中处理事件。如果一个 bean 实现 ApplicationListener,那么每次 ApplicationEvent 被发布到 ApplicationContext 上,那个 bean 会被通知。
为了监听上下文事件,一个 bean 应该实现只有一个方法 onApplicationEvent() 的 ApplicationListener 接口。
定义的两个监听事件的类,就是bean,需要实现接口,并实现onApplicationEvent方法,方法中需要传递进去spring的5种内置类型的事件,这样,当主程序中,ApplicationContext执行相对应类型的事件时候(如事件是contextstartedevent,当上下文执行context.start方法,那么实现onApplicationEvent方法的类,就是bean将收到通知,就是执行该方法。)
主函数:
配置文件bean.xml
(注意:配置文件中,仍然要把上面的两个bean的相关配置,写入xml)
1.5.2 spring中的自定义事件
步骤:
(一)自定义事件customevent需要扩展ApplicationEvent,并且,需要创建构造函数,继承自父类。传入的source是事件发布类publisherEvent的实现类publish。
(二)定义事件发布类。
事件发布类作为需要实现ApplicationEventPublisherAware,另外,需要在XML配置文件中声明这个类为bean。
容器之所以识别该bean作为事件发布者,就是因为实现了ApplicationEventPublisherAware该接口。
然后,既然作为发布类,就需要定义发布publish方法:首先实现set属性,对ApplicationEventPublisher的对象,set赋值,然后publisher.publishEvent(),加入该发布者对应的自定义的事件类,就可以等待事件发生。(customEventPublisher发布者,事件自然是customEvent事件)
(三)定义事件监听类
同上节内容。该类作为监听bean,也需要配置在XML文件中。
(四)主程序
由于事件与ApplicationContext直接关联,自然需要创建上下文对象;然后在上下文对象中获取发布者,context.getBean(publisher),获取发布者;然后获得的发布者实例对象,调用publish()方法,实现自定义事件的监听。
1.3.5 装饰模式
装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。
要求在不改变原类文件和适用继承的情况下,动态地扩展一个对象地功能。它是通过创建一个包装对象,也就是装饰来包裹真实地对象。
关系图如下:
source是被装饰类,decorator是装饰类。
public class Decorator implements Sourceable {
private Sourceable source;
public Decorator(Sourceable source){
super();
this.source = source;
}
@Override
public void method() {
System.out.println("before decorator!");
source.method();
System.out.println("after decorator!");
}
}
测试类:
public class DecoratorTest {
public static void main(String[] args) {
Sourceable source = new Source();
Sourceable obj = new Decorator(source);
obj.method();
}
}
特点:
1.装饰对象和真实对象具有相同地接口。这样客户端对象就能以真实对象相同地方式和装饰对象交互
2.装饰对象包含一个真实对象地引用(GameObject)
3.装饰对象接受所有来自客户端的请求,它把这些请求转发给真实对象
4.装饰对象可以在转发这些以前或者以后增加一些附加功能,这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展
适用条件:
1.需要扩展一个类的功能,或给一个类添加附加职责
2.需要动态的给一个对象添加功能,这些功能还可以再动态的撤销
3.需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使得继承关系变得不现实
4.当不能采用生成子类的方法进行扩充时,一种情况是:可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类
优点:
1.Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性
2.通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合
缺点:
1.这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性
2.装饰模式会导致设计出来许多小类,如果过度使用,会使程序变得很复杂
3.装饰模式是针对抽象组件(Component)类型编程,但是,如果要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。
装饰器模式的应用场景:
1、需要扩展一个类的功能。
2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)
缺点:产生过多相似的对象,不易排错!
1.3.6 模板方法模式(spring的refresh>onfresh)
一个抽象类中,有一个主方法,再定义1...n个方法,可以是抽象的,也可以是实际的方法,定义一个类,继承该抽象类,重写抽象方法,通过调用抽象类,实现对子类的调用,先看个关系图:
在抽象类abstract中定义一个模板方法public calculate(string),然后调用本身的其他方法完成其功能,在定义一个abstract public calculate(int)方法,定义类继承该抽象类并override抽象方法,并由原abstract类calculate(string)调用。子类实现的方法为真正的逻辑。这样,就可以用抽象类模板方法的调用,分别调用不同逻辑的实现方法。
public abstract class AbstractCalculator {
/*主方法,实现对本类其它方法的调用*/
public final int calculate(String exp,String opt){
int array[] = split(exp,opt);
return calculate(array[0],array[1]);
}
/*被子类重写的方法*/
abstract public int calculate(int num1,int num2);
public int[] split(String exp,String opt){
String array[] = exp.split(opt);
int arrayInt[] = new int[2];
arrayInt[0] = Integer.parseInt(array[0]);
arrayInt[1] = Integer.parseInt(array[1]);
return arrayInt;
}
}
public class Plus extends AbstractCalculator {
@Override
public int calculate(int num1,int num2) {
return num1 + num2;
}
}
public class StrategyTest {
public static void main(String[] args) {
String exp = "8+8";
AbstractCalculator cal = new Plus();
int result = cal.calculate(exp, "\\+");
System.out.println(result);
}
}
重点:
需要abstract class和abstract 方法,这个两个需要继承并实现具体的方法。方法主逻辑是final且非抽象的。
就是抽象类定义一个模板方法,并实现其自身调用,设置一个抽象方法,让实现类去override该方法实现具体逻辑。
1.3.7 委派模式
委派模式是一种行为型模式,它允许对象用组合去实现像继承一样的代码复用。在委派模式中,对象通过委托第二个对象(也就是被委派对象)来处理请求。
换句话说,跟代理模式有点像,都要对另外的对象做处理,但是不同的是,代理模式更多的是注重代理的过程,也就是如何去实现对被代理对象的增强或其他动作;委派模式更多的是注重结果,就是委托第三方对象来处理请求从而最终得到的效果。
Boss
发出指令要Leader
去执行,但是Leader
不会自己去做,而是把这些指令肯跟员工实际情况分发给对应的员工去完成,这样就完成了委派。
这里的关键在leader有registry表,所有委派对象这里注册,可以根据请求选择第三方委派对象处理。
public interface Employee {
/**
* 接收任务指令工作
* @param command
*/
void working(String command);
}
public class EmployeeC implements Employee{
@Override
public void working(String command) {
System.out.println("我接到委派【" + command + "】,要开始编码coding了" );
}
}
public class EmployeeW implements Employee {
@Override
public void working(String command) {
System.out.println("我接到委派【" + command + "】,要开始写需求writing了" );
}
}
leader有所有委派者的注册信息
public class Leader {
private final Map<String, Employee> register = new HashMap<>();
public Leader() {
register.put("writing", new EmployeeW());
register.put("coding", new EmployeeC());
}
public void doing(String command) {
Optional.ofNullable(register.get(command)).orElseThrow(() -> new RuntimeException("命令不存在")).working(command);
}
}
public class Boss {
public void command(String command, Leader leader) {
leader.doing(command);
}
}
委派流程就实现了,
new Boss().command("coding", new Leader());
标签:String,--,Spring,模式,class,对象,new,设计模式,public
From: https://www.cnblogs.com/LBJboy/p/17197931.html