总原则:开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类等,后面的具体设计中我们会提到这点。
首先,简单工厂模式不属于23中涉及模式简单工厂模式模式分为三种:普通简单工厂、多方法简单工厂、静态方法简单工厂。
普通简单工厂
就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。首先看下关系图:
举例如下:(我们举一个发送邮件和短信的例子)
首先,创建二者的共同接口:
public interface Sender { void send(); }
其次,创建实现类
Mail:
public class MailSender implements Sender{ @Override public void send() { System.out.println("this is Mail Sender"); } }
Sms:
public class SmslSender implements Sender{ @Override public void send() { System.out.println("this is Sms Sender"); } }
一个测试中需要用到的检查返回类:
public class CheckValue implements Sender{ @Override public void send() { System.out.println("check Value"); } }
最后,建工厂类:
public class SendFactory { public Sender produce(String type) { if ("mail".equals(type)) { return new MailSender(); } if ("sms".equals(type)) { return new SmslSender(); } return new CheckValue(); } }
我们来测试一下
public class StartFactory { public static void main(String[] args) { Sender sender = new SendFactory().produce("mail"); sender.send(); } }
输出:
this is Mail Sender
多个方法
是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。关系图:
将上面的代码做下修改,改动下SendFactory类就行,如下:
public class SendFactory { Sender produceSms() { return new SmslSender(); } Sender produceMail() { return new MailSender(); } }
测试类如下:
public class StartFactory { public static void main(String[] args) { Sender sender = new SendFactory().produceMail(); sender.send(); } }
输出结果如下:
this is Mail Sender
多个静态方法
将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可:
public class SendFactory { static Sender produceSms() { return new SmslSender(); } static Sender produceMail() { return new MailSender(); } }
测试方法:
public class StartFactory { public static void main(String[] args) { Sender sender = SendFactory.produceMail(); sender.send(); } }
输出:
this is Mail Sender
总体来说,工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。
工厂方法模式(Factory Method)
简单工厂模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到工厂方法模式,创建一个工厂接口和创建多个工厂实现类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。
观察UML类图 我们需要两个接口他们分别是代表产品的,Sender接口和代表工厂的Provider接口 .
所以我们第一步还是先去创建接口,然后用类实现它.
接口 Sender :
public interface Sender {
void send(); }
两个实现类:
Mail:
public class MailSender implements Sender{ @Override public void send() { System.out.println("this mail factory method"); } }
Sms:
public class SmsSender implements Sender{ @Override public void send() { System.out.println("this sms factory method"); } }
工厂接口 MethodFactory :
public interface MethodFactory { Sender produce(); }
两个实现类:
mail:
public class SendMailFactory implements MethodFactory { @Override public Sender produce() { return new MailSender(); } }
sms:
public class SendSmsFactory implements MethodFactory { @Override public Sender produce() { return new SmsSender(); } }
测试类:
public class StartFactroy { public static void main(String[] args) { MethodFactory methodFactory = new SendSmsFactory(); Sender sender = methodFactory.produce(); sender.send(); } }
输出结果:
this sms factory method
其实这个模式的好处就是,如果你现在想增加一个功能:发及时信息,则只需做一个实现类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。这样做,拓展性较好!
使用场景:
1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。
注意事项:
作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
参考资料:《设计模式-工厂方法设计模式》