设计模式之简单工厂模式与工厂方法模式
2019-08-27 07:14:58来源:博客园 阅读 ()
设计模式之简单工厂模式与工厂方法模式
1 简单工厂设计模式
1.1简介
简单工厂模式属于创建者模式,又叫做静态工厂方法模式,但不属于23中GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为不同工厂模式的一个特殊实现。
1.2简单工厂模式的角色
工厂类(creator)角色:简单工厂模式的核心,负责创建所有实例的逻辑。工厂类提供静态方法,根据传入的参数创建所需的产品对象。
抽象产品(Product)角色:简单工厂模式创建的所有的对象的父类,负责描述所有实例的公共接口。可以是抽象类或接口。
具体产品(Concrete Product)角色:是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。
1.3简单工厂模式的UML图
1.4例子
需求:实现简单计算器+、-、*、/功能。
第1步:定义公共接口,接口中定义计算结果的方法。
public interface ICalculable { double getResult(double numberA, double numberB) throws Exception; }
第2步:定义加、减、乘、除4个具体的实现类。
public class CalculateAdd implements ICalculable { @Override public double getResult(double numberA, double numberB) { return numberA + numberB; } } public class CalculateDiv implements ICalculable { @Override public double getResult(double numberA, double numberB) throws Exception { if (numberB == 0) { throw new Exception("不能除以0"); } return numberA / numberB; } } public class CalculateMul implements ICalculable { @Override public double getResult(double numberA, double numberB) { return numberA * numberB; } } public class CalculateSub implements ICalculable { @Override public double getResult(double numberA, double numberB) { return numberA - numberB; } }
第3步:创建工厂类,编写静态方法,根据方法参数创建相应对象实例并返回。
public class CalculationFactory { public static ICalculable createCalculation(String operator) { ICalculable calculable = null; switch (operator) { case "+": calculable = new CalculateAdd(); break; case "-": calculable = new CalculateSub(); break; case "*": calculable = new CalculateMul(); break; case "/": calculable = new CalculateDiv(); break; } return calculable; } }
第4步:编写测试类
public class CalculationTest { public static void main(String[] args) { try { Scanner scanner = new Scanner(System.in); System.out.println("请输入数字A"); String strA = scanner.nextLine(); System.out.println("请输入数字B"); String strB = scanner.nextLine(); System.out.println("请输入操作符:(+、-、*、/)"); String strOperate = scanner.nextLine(); double result = CalculationFactory.createCalculation(strOperate) .getResult(Double.parseDouble(strA),Double.parseDouble(strB)); System.out.println("计算结果=" + result); } catch (Exception e) { e.printStackTrace(); System.out.println("输入有误:" + e.getMessage()); } } }
下面来看一下这个这个例子的UML图,白色虚线为依赖关系,绿色虚线为接口实现类关系
1.5小结
简单工厂模式的优点:工厂类中包含了必要的逻辑判断,根据客户端传入的参数,动态实例化相关的类,对客户端来说,去除了对具体产品的依赖。
缺点:添加新的功能时,除了添加产品类外,需要修改工厂类,违反了开放-关闭原则。
2 、工厂方法设计模式
2.1简介
定义一个用户创建对象的接口,让子类决定实例化那一个类。工厂方法使一个类的实例化延迟到其子类。
2.2 工厂方法模式UML图(本图摘自《大话设计模式》)
2.3改进简单工厂中简单计算器的实现
第一步:创建工厂接口,定义工厂方法,该方法返回产品的抽象类对象(Product)。
public interface IFactory { ICalculable createCalculation(); }
第二步:创建工厂接口的实现类对象,实现工厂方法功能(方法里面返回具体的产品实现类对象)
public class AddFactory implements IFactory { @Override public ICalculable createCalculation() { return new CalculateAdd(); } } public class DivFactory implements IFactory { @Override public ICalculable createCalculation() { return new CalculateDiv(); } } public class MulFactory implements IFactory { @Override public ICalculable createCalculation() { return new CalculateMul(); } } public class SubFactory implements IFactory { @Override public ICalculable createCalculation() { return new CalculateSub(); } }
第三步:编写测试代码
public static void main(String[] args) { try { IFactory factory = new AddFactory(); ICalculable calculation = factory.createCalculation(); calculation.getResult(1, 2); } catch (Exception e) { e.printStackTrace(); } }
下面来看一下工厂方法模式在本例中的UML图
2.4工厂方法模式的优缺点
优点:添加新功能时,只需要添加此功能对应的计算类(实现ICalculable接口)和相应的工厂类(实现IFactory接口),符合开放-关闭原则。
缺点:把简单工厂的内部逻辑判断转移到客户端代码进行,增加功能需要修改客户端代码。
到这里肯定有小伙伴会说:没看出来工厂方法模式比简单工厂模式好在哪里呀,只是将简单工厂模式中工厂类的判断逻辑转移到了工厂方法模式中的客户端中进行。
下面再讲一个例子:雷锋帮助老人扫地、洗衣、买米的案例。
第1步:定义雷锋类(相当于Product),通常情况下Product为抽象类或接口,ConcreteProduct类中重写Product中的抽象方法,在这里因为学习雷锋做好事的人做的事情是和雷锋做的事情是一样的,所以雷锋类直接定义做好事的具体细节,学习雷锋做好事的人只需要继承雷锋类就可以了(学习雷锋做好事的人相当于ConcreteProduct)
public class LeiFeng { public void sweep() { System.out.println("扫地"); } public void wash() { System.out.println("洗衣"); } public void buyRice() { System.out.println("买米"); } }
第2步:定义学习雷锋做好事的人的类:学雷锋的大学生类和社区志愿者类,让他们都继承雷锋类。
/** * 学雷锋的志愿者 */ public class Volunteer extends LeiFeng { } /** * 学雷锋的大学生 */ public class Undergraduate extends LeiFeng { }
第3步:编写简单工厂类
public class SimpleFactory { public static LeiFeng createLeifeng(String type) { LeiFeng leiFeng = null; switch (type) { case "学雷锋的大学生": leiFeng = new Undergraduate(); break; case "社区志愿者": leiFeng = new Volunteer(); break; } return leiFeng; } }
第4步:让三个学生分别帮助老人扫地、洗衣、买米。
public static void main(String[] args) { LeiFeng leifeng1 = SimpleFactory.createLeifeng("学雷锋的大学生"); leifeng1.sweep(); LeiFeng leifeng2 = SimpleFactory.createLeifeng("学雷锋的大学生"); leifeng2.wash(); LeiFeng leifeng3 = SimpleFactory.createLeifeng("学雷锋的大学生"); leifeng3.buyRice(); }
看到上面的代码,应该有小伙伴闻到了坏味道,因为有3处相同的代码(在代码中我们应该尽量减少重复的代码,第一是容易写错,第二是如果要修改的话,所有的地方都要修改)。
第5步:将简单工厂模式改为工厂方法模式。创建工厂接口,定义工厂方法,该方法返回雷锋类(LeiFeng)。
public interface IFactory { LeiFeng createLeiFeng(); }
第6步:创建工厂接口的实现类对象,实现工厂方法功能。在这里就是定义学雷锋的大学生工厂和社区志愿者工厂,实现工厂接口的方法,在方法中分别创建学雷锋的大学生类和社区志愿者类。
/** * 学雷锋的大学生工厂,负责创建大学生对象 */ public class UndergraduateFactory implements IFactory { @Override public LeiFeng createLeiFeng() { return new Undergraduate(); } } /** * 社区志愿者工厂,负责创建社区志愿者对象 */ public class VolunteerFactory implements IFactory { @Override public LeiFeng createLeiFeng() { return new Volunteer(); } }
第7步:实现第4步相同的功能。
public static void main(String[] args) { IFactory factory = new UndergraduateFactory(); //如果要将大学生换成志愿者,只需要修改这一处就可以了 LeiFeng leiFeng1 = factory.createLeiFeng(); LeiFeng leiFeng2 = factory.createLeiFeng(); LeiFeng leiFeng3 = factory.createLeiFeng(); leiFeng1.sweep(); leiFeng2.wash(); leiFeng3.buyRice(); }
再来看一下UML图
到这里,小伙伴们应该可以看出来工厂方法模式比简单工厂方法更好的地方了,工厂方法模式克服了简单工厂违反开放-封闭原则的缺点,又保持了封装对象创建过程的优点。这样在更换具体的实现对象时(比如将大学生换成社区志愿者),不需要大的改动就可以实现。降低了客户端程序与产品对象的耦合,工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态,工厂方法模式既保持了简单工厂的优点,又克服了简单工厂模式添加新功能需要修改原有类的缺点。
写此博客是为了日后方便复习,加深印象,交流学习。对于其中的错误之处,欢迎网友积极指出,本人一定听取意见并进行合理改正。
原文链接:https://www.cnblogs.com/ethan-wu/p/10745902.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- 如何干掉 if else 策略+工厂 2020-06-11
- Linux简单命令的学习 2020-06-10
- 因为命名被diss无数次。简单聊聊编程最头疼的事情之一:命名 2020-06-10
- 设计模式-委派/策略模式 2020-06-09
- 「starter推荐」简单高效Excel 导出工具 2020-06-08
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash