问题:我们总是会遇到这样的问题---在一个复杂系统中,有一些依赖性,关联性低的功能,比如某些场景中需要发送一个邮件。这个时候我们需要这个“发邮件”的功能,具有低耦合的特性,只需要调用传入参数便可实行这样的功能。但是为了易用性,通常会给这样的--暂且称为插件的东西,加上一个开关。
代理模式:顾名思义,代理,指的是b-a-c,b需要c的功能,但是要经过a再到达c,因此在a上添加一些条件,a就变成了一个开关。举个现实的例子,我们的家里都有电灯,但是我们不希望它一直亮着,想要它亮的时候就亮,灭的时候就灭。在这里我们的手就是b,开关就是a,电灯就是c。
要点:面向接口编程
begin
b-a-c这样的过程,归根结底是要实现c的功能,所以第一步我们需要一个具体实现的过程
c(发邮件):
1,定义一个发邮件的接口
package plug.inter;
public interface stmp_inter{
public boolean stmp();
}
2,写一个具体发邮件的功能类-stmp_imp.java,实现接口
package plug.imp;
import plug.inter.stmp_inter;
import plug.plugControl.plugs;
import javax.mail.*;
import javax.mail.internet.*;
import javax.mail.internet.MimeMessage.RecipientType;
import java.util.Properties;
public class stmp_imp implements stmp_inter {
private String from;
private String to;
private String title;
private String val;
private String key;
/*设置发送者邮箱,接受者邮箱,邮件题目,邮件服务器授权码*/
public stmp_imp(String from, String to, String title, String val, String key){
this.from=from;
this.to=to;
this.title=title;
this.val=val;
this.key=key;
stmp();
}
@Override
public boolean stmp() {
Properties properties = new Properties();
/*链接协议*/
properties.put("mail.transport.protocol", "smtp");
/*服务器地址*/
properties.put("mail.smtp.host", "smtp.qq.com");
/*服务器端口*/
properties.put("mail.smtp.port", 465);
/*暂不知道*/
properties.put("mail.smtp.auth", "true");
/*使用ssh链接协议*/
properties.put("mail.smtp.ssl.enable", "true");
/*得到回话对象*/
Session session = Session.getInstance(properties);
Message message = new MimeMessage(session);
try{
message.setFrom(new InternetAddress(from));
message.setRecipients(RecipientType.TO,new InternetAddress[] {
new InternetAddress(to)
});
message.setSubject(title);
message.setText(val);
Transport transport = session.getTransport();
transport.connect(from, key);
transport.sendMessage(message, message.getAllRecipients());
return true;
}
catch(Exception e){
return false;
}
}
@Override
public boolean getState() {
return false;
}
}
3,代理功能类,实现接口
package plug.imp;
import plug.inter.stmp_inter;
import plug.plugControl.plugs;
/*
* 代理模式
* 使用时上转型
* */
public class stmp_switch implements stmp_inter{
/*swit为发邮件功能当前状态,是否开启*/
private static boolean swit;
private stmp_imp stm;
private String from;
private String to;
private String title;
private String val;
private String key;
public void stmp_set(String from, String to, String title, String val, String key){
this.from=from;
this.to=to;
this.title=title;
this.val=val;
this.key=key;
}
@Override
public boolean stmp() {
if (stm==null&&swit){
this.stm=new stmp_imp(from,to,title,val,key);
stm.stmp();
return true;
}else{
if(swit){
stm.stmp();
return true;
}else{
return false;
}
}
}
/*设置邮件状态*/
public void stmp(boolean bo){
this.swit=bo;
}
public boolean getState(){
return swit;
}
}
4,调试
package plug.inter;
import plug.imp.stmp_switch;
public class test {
public static void main(String[] arge){
stmp_switch p=new stmp_switch();
System.out.println("发邮件插件当前状态为"+p.getState());
/*开启插件*/
p.stmp(true);
/*设置信息*/
p.stmp_set("510009842@qq.com","1990557780@qq.com","test","test","xxxxxxxxxx");
/*发送邮件*/
p.stmp();
}
}
5,结果
6,由此发邮件的插件就做好了,但是这里有两个问题,
(1)我们并不希望只使用一个插件,但是多个插件放在一起就需要一个有效的管理。我们想要装一台电灯,从接电线到装开关,无疑这是一个专业的事情,这个时候我们会去专业的电工,电工按照固定的步骤装好电灯。同样的我们我们也希望只提供材料就能直接按开关亮灯。那么就需要引入另一种模式-工厂模式。
(2)我们想要灯亮,只想要找到开关,按下开关就可以了,但是有很多的灯,有的时候你并不知道,那个开关对应的是哪个灯,这个时候我们需要给开关贴上标签。
7,定义插件工厂接口
package plug.plugControl;
public interface plugs{
Object draw(String clsz);
}
8,配置插件信息
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!-- 插件名-->
<name>stmp</name>
<!-- 插件开关-->
<claza>plug.imp.stmp_switch</claza>
<!-- 插件实现类-->
<claza_name>stmp</claza_name>
<!-- 作者-->
<admin>巫云</admin>
<!-- 介绍-->
<persent>发邮件</persent>
</root>
9,新建插件信息实体
package plug.plugControl;
/*
* plug信息
*
* */
public class bean_plug {
private String name;
private String claza;
private String claza_name;
private String admin;
private String persent;
private boolean state;
public boolean isState() {
return state;
}
public void setState(boolean state) {
this.state = state;
}
public String getAdmin() {
return admin;
}
public void setAdmin(String admin) {
this.admin = admin;
}
public String getPersent() {
return persent;
}
public void setPersent(String persent) {
this.persent = persent;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClaza() {
return claza;
}
public void setClaza(String claza) {
this.claza = claza;
}
public String getClaza_name() {
return claza_name;
}
public void setClaza_name(String claza_name) {
this.claza_name = claza_name;
}
}
10,扫描配置文件
package plug.plugControl;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.util.*;
/*
* 扫描所有插件并装载插件信息
* */
public class scans_plug{
private static scans_plug kl=new scans_plug();
public static scans_plug getObj(){
return kl;
}
public Object draw(HttpServletRequest request) {
List plugzz = new LinkedList();
String path=request.getServletContext().getRealPath("WEB-INF/classes/plug/regist");
ArrayList<String> fileName = new ArrayList<String>();
File files = new File(path);
File[] filesList = files.listFiles();
for (File file : filesList) {
try {
DocumentBuilderFactory factory =DocumentBuilderFactory.newInstance();
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc=builder.parse(file);
NodeList name=doc.getElementsByTagName("name");
NodeList claza=doc.getElementsByTagName("claza");
NodeList claza_name=doc.getElementsByTagName("claza_name");
NodeList admin=doc.getElementsByTagName("admin");
NodeList persent=doc.getElementsByTagName("persent");
bean_plug be=new bean_plug();
be.setName(name.item(0).getFirstChild().getNodeValue());
be.setClaza(claza.item(0).getFirstChild().getNodeValue());
be.setClaza_name(claza_name.item(0).getFirstChild().getNodeValue());
be.setAdmin(admin.item(0).getFirstChild().getNodeValue());
be.setPersent(persent.item(0).getFirstChild().getNodeValue());
plugzz.add(be);
} catch (Exception e) {
e.printStackTrace();
}
}
return plugzz;
}
}
11,侦听插件状态
新建状态接口
package plug.plugControl;
public interface state_plug {
boolean getState();
}
使开关继承状态接口
package plug.inter;
import plug.plugControl.plugs;
import plug.plugControl.state_plug;
public interface stmp_inter extends state_plug {
public boolean stmp();
}
11,组建工厂核心
package plug.plugControl;
import plug.imp.stmp_switch;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/*
* 反射创建plug对象
* */
public class draw_plug implements plugs {
@Override
public Object draw(String clsz) {
try {
Class c=Class.forName(clsz);
Constructor constructor=c.getConstructor();
Object o=constructor.newInstance();
return o;
} catch (ClassNotFoundException e) {
return null;
} catch (NoSuchMethodException e) {
return null;
} catch (InstantiationException e) {
return null;
} catch (IllegalAccessException e) {
return null;
} catch (InvocationTargetException e) {
return null;
}
}
}
12,组建工厂
package plug.plugControl;
import javax.servlet.http.HttpServletRequest;
import java.io.ObjectStreamClass;
import java.util.List;
import java.util.Map;
/**
* 根据扫描的结果组件插件工厂
*/
public class plugFactory {
public Object getPlug(String plug, HttpServletRequest request){
List plugst=(List) scans_plug.getObj().draw(request);
for(Object be:plugst ){
bean_plug bes= (bean_plug) be;
if(plug.equalsIgnoreCase(bes.getClaza_name())){
state_plug c=(state_plug)new draw_plug().draw(bes.getClaza());
bes.setState(c.getState());
return new draw_plug().draw(bes.getClaza());
}
}
return null;
}
}
14,使用
/*
*建立插件工厂
*/
plugFactory plugFactorys=new plugFactory();
/* *//*
选择插件*//*
stmp_switch p=(stmp_switch) plugFactorys.getPlug("STMP",request);
*//*设置插件状态 true/false*//*
p.stmp(true);
*//*设置邮件 (发件人,收件人,题目,内容,邮件授权码)*//*
p.stmp_set("510009842@qq.com","2235733688@qq.com","test","test","smviuilfoqdocbbf");
*//*发送邮件*//*
p.stmp();*/