spring常见设计模式之工厂模式与外观模式
Posted 我就是红红
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring常见设计模式之工厂模式与外观模式相关的知识,希望对你有一定的参考价值。
工厂模式分为简单工厂模式, 工厂方法模式以及抽象工厂模式,其中以抽象工厂模式在我们的spring中应用的最为广泛. 抽象 == abstract 我们在观察一些源码的时候,应该不难发现一些抽象的类, 例如AbstractApplicationContext中有一个方法是 getBean()方法,获取上下文的.
首先我们先看简单工厂模式,什么是简单工厂模式呢? 其实很简单, 就是我们创建工厂的类,完成对同一接口的不同类的实例的创建.简单来说,就是,我现在要发送短信以及发送邮件,那么,首先我创建一个公共的接口类作为入口,然后通过不同的类去实现它完成我的功能. 代码如下:
public interface Send {
/**
* 公告接口入口
* @return
*/
boolean send();
}
public class SmsSend implements Send {
/**
* 发送短信
* @return
*/
public boolean send() {
System.out.println("发送短信");
return false;
}
}
public class MailSend implements Send {
/**
* 发送邮件
* @return
*/
public boolean send() {
System.out.println("发送邮件");
return false;
}
}
接下来我们创建一个工厂类:
public class SendFactory{
public Send send(String type) {
if ("mail".equals(type)) {
return new MailSend();
} else if ("sms".equals(type)) {
return new SmsSend();
} else {
System.out.println("请输入正确的类型!");
return null;
}
}
}
创建一个测试类我们来测试一下:
public class EasyFactoryTest {
/**
* 简单工厂测试
*/
public static void main(String[] args) {
SendFactory sendFactory = new SendFactory();
Send mail = sendFactory.send("mail");
mail.send();
}
}
测试结果如下:
这种方式是简单的工厂模式的应用,我们应该也能看出来,如果我在测试过程中写错了mail,那么执行的结果一定是 "请输入正确的类型!" ,这种将操作权交给用户的行为肯定是不可取的.而且,当我们需要在其中再进行添加一条消息推送的时候呢,这个时候必然需要去改动我们的代码.所以这种方式不可取.
这个时候我们对,简单工厂模式进行了一段改进,就是多方法模式也就是多个工厂方法
还是以第一个例子为例(后面同样是,不再举其他例子了),我们只需要修改SendFactory工厂类就可以了.
public class SendFactory{
public Send sendSms(){
return new SmsSend();
}
public Send sendMail(){
return new MailSend();
}
}
代码和简单工厂模式一致
看下我们的测试类:
public class FunctionFactoryTest {
/**
* 工厂方法测试
*/
public static void main(String[] args) {
SendFactory sendFactory = new SendFactory();
Send mail = sendFactory.sendMail();
mail.send();
}
}
执行结果如下:
很明显,我们改进了用户手动输入的弊端,但是第二个还是没有满足,我们的一切都依赖于我们的Factory类,一旦我们需要修改或添加方法时,我们必然要去修改我们的接口.这不满足于闭包原则.再次在当前的模式中,工厂类需要我们自己去进行实例.
接下来的静态工厂方法是针对于工厂模式静态化去做的,目的在于能够让系统帮我们去实例化,我们只需要调用即可.
public class SendFactory {
public static Send sendSms(){
return new SmsSend();
}
public static Send sendMail(){
return new MailSend();
}
}
public static void main(String[] args) {
Send send = SendFactory.sendMail();
send.send();
}
大多数情况下,我们一般会选择静态工厂方法.
刚刚也提到,简单工厂特别依赖于我们的工厂类,如果想要扩展我们的程序,那么势必需要去改动我们的工厂类,这违反了闭包原则.所以我们怎么办呢?我们可以这样来
创建一个发送消息的接口方法
public interface Send {
void send();
}
两个实现类,SmsSend以及 MailSend
public class SmsSend implements Send {
public void send() {
System.out.println("短信发送");
}
}
public class MailSend implements Send {
public void send() {
System.out.println("邮件发送");
}
}
我们创建工厂方法接口
public interface Common {
void commonSend();
}
然后我们分别创建两个工厂,SmsFactory短信工厂以及MailFactory邮件工厂分别实现Common公共接口
public class SmsFactory implements Common{
public Send commonSend() {
return new SmsSend();
}
}
public class MailFactory implements Common {
public Send commonSend() {
return new MailSend();
}
}
我们测试一下
其实这个模式的好处就是,如果你现在想增加一个功能:发及时信息,则只需做一个实现类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。这样做,拓展性较好!
这个时候我在想,虽然这个好用,但是我实现一个简单的功能就创建这么多的实例是不是太浪费了,这个时候我们来看抽象工厂模式是什么样子.
同样的,我们创建一个公共的接口
public interface Sender {
/**
* 发送短信/ 邮件入口方法
* @param agr1
* @param arg2
*/
void send(String agr1, Integer arg2);
}
然后我们创建一个抽象的工厂
抽象工厂是用户的主入口 在Spring中应用得最为广泛的一种设计模式 易于扩展
public abstract class AbstractFactory {
public abstract Sender sendSms();
public abstract Sender sendMail();
}
接下来我们创建一个发送消息的工厂类,继承我们的抽象工厂
public class SenderFactory extends AbstractFactory {
@Override
public Sender sendSms() {
return new SendSms();
}
@Override
public Sender sendMail() {
return sendMail();
}
}
接下来我们测试一下
其实抽象工厂和工厂方法模式两个的区别其实在代码表现层面区别不大
区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。 工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
工厂方法创建 "一种" 产品,他的着重点在于"怎么创建",也就是说如果你开发,你的大量代码很可能围绕着这种产品的构造,初始化这些细节上面。也因为如此,类似的产品之间有很多可以复用的特征,所以会和模版方法相随。
抽象工厂需要创建一些列产品,着重点在于"创建哪些"产品上,也就是说,如果你开发,你的主要任务是划分不同差异的产品线,并且尽量保持每条产品线接口一致,从而可以从同一个抽象工厂继承。
所以说抽象工厂就像工厂,而工厂方法则像是工厂的一种产品生产线
外观模式
外观模式是为了解决类与类之间关联关系的,就像spring一样,将类与类之间的关系放到了配置文件当中,而外观模式就是将他们的关系放在一个Facade类中,降低了类类之间的耦合度,该模式中没有涉及到接口;
我们以电脑的开机关机为例:
public class Cpu {
public void startup(){
System.out.println("cpu starting");
}
public void shutdown(){
System.out.println("cpu shutdown");
}
}
public class Disk {
public void startup(){
System.out.println("Disk starting");
}
public void shutdown(){
System.out.println("Disk shutdown");
}
}
public class Memory {
public void startup(){
System.out.println("memory starting");
}
public void shutdown(){
System.out.println("memory shutdown");
}
}
在这里我们能够看到,这三个实例中的方法是相同的,但是我们在启动电脑的时候,这三个实例都需要进行启动,我们不能每次都去创建三个实例,如果实例更多呢.那么不足之处就显而易见了.
首先,我们看,我们是启动的电脑,那么我是不是可以先创建一个电脑的类Computer
public class Computer {
private Cpu cpu;
private Memory memory;
private Disk disk;
public Computer(){
cpu = new Cpu();
memory = new Memory();
disk = new Disk();
}
public void startup(){
System.out.println("start the computer!");
cpu.startup();
memory.startup();
disk.startup();
System.out.println("start computer finished!");
}
public void shutdown(){
System.out.println("begin to close the computer!");
cpu.shutdown();
memory.shutdown();
disk.shutdown();
System.out.println("computer closed!");
}
}
在这里,我将我需要逐步进行的实例放到了我创建的另外的实例中,并且添加了统一的开关方法修改
那么我在启动的时候,是不是可以理解为我直接调用Computer里面的startup方法或者shutdown方法就可以呢?我们测试一下
如果我们没有Computer类,那么,CPU、Memory、Disk他们之间将会相互持有实例,产生关系,这样会造成严重的依赖,修改一个类,可能会带来其他类的修改,这不是我们想要看到的,有了Computer类,他们之间的关系被放在了Computer类里,这样就起到了解耦的作用,这,就是外观模式.
其实我们在项目中经常会看到这些设计模式,当我们理解了它的原理之后,那么它将不在"神奇"
以上是关于spring常见设计模式之工厂模式与外观模式的主要内容,如果未能解决你的问题,请参考以下文章