一、工厂方法模式
工厂模式1:普通工厂方法模式
1.常量定义部分
/** * 常量定义类,所有公用的常量定义均在此类中定义 */ package com.le.global; public class Const { /** * 定义不同工人类型的常量 */ public static final byte SENDER_MAIL = 1; public static final byte SENDER_SMS = 2; }
2.实例接口定义部分
/** * 发送者接口定义,所有工人通用的方法都定义在这里,由具体工人类实现对应方法 */ package com.le; public interface ISender { public void send(); }
3.实例类定义部分
3.1邮件发送实例类定义部分
/** * 邮件发送工人具体类,实现邮件发送的具体内容 */ package com.le.impl; import com.le.ISender; public class MailSenderImpl implements ISender { public void send() { System.out.println("Mail.send"); } }
3.2短信发送实例类定义部分
/** * 短信发送工人具体类,实现短信发送的具体内容 */ package com.le.impl; import com.le.ISender; public class SmsSenderImpl implements ISender { public void send() { System.out.println("SMS.send"); } }
4.工厂类定义部分
/** * 消息发送工厂类,用于根据条件初始化一个具体工人实例 */ package com.le; import com.le.global.Const; import com.le.impl.MailSenderImpl; import com.le.impl.SmsSenderImpl; public class SenderFactory { /** * 传入类型,返回一个具体的工人 * * @param AType * @return 若找到对应类型则直接返回一个新的对应工人实例,否则返回null */ public static ISender produce(int AType) { switch (AType) { case Const.SENDER_MAIL: return new MailSenderImpl(); case Const.SENDER_SMS: return new SmsSenderImpl(); default: System.out.println("类型未定义,请输入一个合法的类型"); return null; } } }
5.测试部分
/** * 测试类 */ package com.le; import com.le.global.Const; public class Main { private static ISender sender = null; public static void main(String[] args) { // 邮件发送 sender = SenderFactory.produce(Const.SENDER_MAIL); sender.send(); // 短信发送 sender = SenderFactory.produce(Const.SENDER_SMS); sender.send(); } }
6.输出内容
Mail.send SMS.send
从上面的代码我们可以看到,我们在实际使用的时候,只需要把实例接口基类ISender、加工厂类SenderFactory定义好即可。然后在具体使用的时候,针对每一种不同操作,实现ISender接口,实现自己的具体send方法;然后在SenderFactory.produce方法中增加一种针对该类型的实例化的返回值即可。而不需要对使用者Main.main方法中的逻辑做任何更改。
这个模式的优点:
- 新增一个新的实现类时,使用者逻辑不用做任何改动,扩展方便
- 逻辑清晰,业务与实现分离
缺点:
- 新增一个新的实现类时,需要同步修改加工厂类,违反了闭包原则
应用场景:在有大量的实现类,并且具有共同的接口时,可以考虑使用工厂方法模式进行创建。
工厂模式2:多工厂方法模式
1.改变工厂类定义部分
/** * 返回一个发送邮件的工人实例 * * @return */ public ISender produceMail() { return new MailSenderImpl(); } /** * 返回一个发送短信的工人实例 * * @return */ public ISender produceSms() { return new SmsSenderImpl(); }
2.改变调用部分
public static void main(String[] args) { //定义工厂类 SenderFactory sf = new SenderFactory(); // 邮件发送 sender = sf.produceMail(); sender.send(); // 短信发送 sender = sf.produceSms(); sender.send(); }
3.输出内容
Mail.send SMS.send
多工厂方法模式与普通工厂模式的区别就是:
普通工厂模式在需要具体实体的时候需要传入一个标识,工厂类根据传入的标识初始化一个对应的实体并返回,有可能传入的标识不合法,导致返回null。
多工厂方法模式是为每个不同的实体类定义了一个方法,这样在使用时绝对不会出错。
个人不推荐这种用法,因为这样实体类比较多的时候会导致代码重用率很低,大家了解一下就可以了!
工厂模式3:静态工厂方法模式
1.改变工厂类定义部分
/** * 返回一个发送邮件的工人实例 * * @return */ public static ISender produceMail() { return new MailSenderImpl(); } /** * 返回一个发送短信的工人实例 * * @return */ public static ISender produceSms() { return new SmsSenderImpl(); }
2.改变调用部分
public static void main(String[] args) { // 邮件发送 sender = SenderFactory.produceMail(); sender.send(); // 短信发送 sender = SenderFactory.produceSms(); sender.send(); }
3.输出内容
Mail.send SMS.send
该模式与多工厂方法模式的区别仅仅是把每个获取实例的方法定义成为一个静态方法,调用时不需要初始化工厂类即可直接获取需要的实例
个人不推荐这种用法,原因与多工厂方法模式一样,代码重用率很低!
二、抽象工厂模式
1.工厂接口定义部分
/** * 工厂接口,所有工厂类实现该类接口 */ package com.le; public interface ISenderFactory { public ISender produce(); }
2.工厂类定义部分
2.1邮件发送工厂类定义部分
/** * 邮件发送工厂类 */ package com.le.factory; import com.le.ISender; import com.le.ISenderFactory; import com.le.impl.MailSenderImpl; public class MailSenderFactory implements ISenderFactory { public ISender produce() { return new MailSenderImpl(); } }
2.2.短信发送工厂类定义部分
/** * 短信发送工厂类 */ package com.le.factory; import com.le.ISender; import com.le.ISenderFactory; import com.le.impl.SmsSenderImpl; public class SmsSenderFactory implements ISenderFactory { public ISender produce() { return new SmsSenderImpl(); } }
3.发送者接口定义部分
/** * 发送者接口定义,所有工人通用的方法都定义在这里,由具体工人类实现对应方法 */ package com.le; public interface ISender { public void send(); }
4.实例类定义部分
4.1.邮件发送实例类定义部分
/** * 邮件发送工人具体类,实现邮件发送的具体内容 */ package com.le.impl; import com.le.ISender; public class MailSenderImpl implements ISender { public void send() { System.out.println("Mail.send"); } }
4.2.短信发送实例类定义部分
/** * 短信发送工人具体类,实现短信发送的具体内容 */ package com.le.impl; import com.le.ISender; public class SmsSenderImpl implements ISender { public void send() { System.out.println("SMS.send"); } }
5.测试部分
/** * 测试类 */ package com.le; import com.le.factory.MailSenderFactory; import com.le.factory.SmsSenderFactory; public class Main { private static ISender sender = null; private static ISenderFactory sf = null; public static void main(String[] args) { //创建邮件发送工厂实例 sf = new MailSenderFactory(); //获取邮件发送实例 sender = sf.produce(); //调用发送方法 sender.send(); //创建短信发送工厂实例 sf = new SmsSenderFactory(); //获取实例 sender = sf.produce(); //发送消息 sender.send(); } }
6.输出内容
Mail.send SMS.send
从上面的代码我们可以知道,抽象工厂模式与普通工厂方法模式的区别:抽象工厂模式是对普通工厂方法模式的进一层封装
不过就算是抽象工厂模式,在每新增一个新的功能时,都需要扩展调用部分,使其支持新增的实例。
个人总结:在遇到一个需要实例化很多实例,并且每个实例在使用时都有共同的特性时,可以考虑使用工厂模式编写代码。推荐使用普通工厂方法来实现,不过需要在获取实例的方法内要做判断,若得到非法值给予默认处理或友好的反馈给调用者。
以上学习资料来自原帖地址