博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式学习02—工厂模式
阅读量:6983 次
发布时间:2019-06-27

本文共 4180 字,大约阅读时间需要 13 分钟。

1、动机与定义
     我们在程序中使用一个对象时,须要new一下,假设须要设置其它值就再初始化一下。比方我要使用一个button,手动new一个矩形button。然后初始化一些值,如显示文字,背景色等。
// 矩形button        IButton btn = new RecButton();        // 初始化其它值        btn.setText("提交");        btn.setBackgroundColor("#00aaff");        // 其它初始化省略        // 圆形button        IButton btn2 = new RoundButton();        btn.setText("关于");        btn.setBackgroundColor("#00aaff");        // 其它初始化省略
     这样写有几个缺点:
     1、写一次没有问题,假设须要100个,就要写100次,太麻烦了。
     2、非常多设置是反复的,比方样例中的背景色。一个系统可能风格统一,仅仅有几种背景色,不须要每次都手动设置。
     3、耦合性太强,client必须知道详细的button创建过程,必须会创建button才行,兴许button的方法改变,client也可要跟着改动,如以后button必须设置大小了,全部client代码都要变动。
     4、反复对象没有控制。比方btn2的关于。可能每一个页面都有。可是每一个页面的这个button都是一模一样的,不是必需每次都创建一遍。

     5、没有封装变化,假如写了100个new RoundButton,兴许这个button发生改变了,我们要改100处代码。
     等等,假设你再细致想想,各种各样的情况下都有各种各样的缺点(当然这么写也有长处的,至少简单嘛,怎样设计没有最好。仅仅有合适的)。那么我们有没有其它方式来规避这些问题呢?事实上我们须要一个对象时,除了自己new之外,还有就是从其它地方获取,我们全然能够把这些button的创建过程放到一起,client使用的时候直接获取即可了。比方以下代码:
public class RoundButtonFactory implements Creater {    public static IButton createButton(String text) {        // 圆形button        IButton btn = new RoundButton();        btn.setText(text);        btn.setBackgroundColor("#00aaff");        return btn;    }}
     
工厂模式定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。
     客户
端使用时,仅仅须要调用createButton即可,屏蔽了底层的详细实现。兴许实现类变化了,仅仅须要改动这种方法即可了;也使client和详细的button实现类解耦开来。事实上这就是最主要的工厂模式。
     简单说就是将要使用的对象抽象出一个接口(产品),另一个接口的创建工厂,每一个详细实现类(产品的实现类)的创建由工厂的实现类创建。

2、结构与类图
     工厂模式通用类图例如以下:
     上面举的样例的类图例如以下:
     工厂方法包括四个角色:
     1、抽象产品(Product):负责定义产品公有属性。
     2、详细产品(ConcreteProduct):详细的产品实现类;
     3、抽象工厂(Creater):抽象的创建类。也就是抽象工厂;
     4、详细工厂(ConcreteCreater):详细创建者。也就是详细工厂,负责详细产品实现类的创建。
3、适用场景及效果(优缺点)
     没有工厂的时候,假如我们要做饭,须要用到火,创建火的同一时候发现须要用到木柴,还要创建一个锯来锯木柴......代码例如以下:
// 创建锯        Saw saw = new Saw ();        // 使用锯,锯木柴        FireWood fw = saw.cut();        // 使用木柴创建火        Fire fire = new WoodFire(fw);
     
能够看到。这种话,做饭的逻辑就依赖了锯、木柴、火等东西,假设使用工厂呢
Fire fire = WoodFireFactroy.create();
     1、具有良好的封装性,逻辑代码清晰,不用new了,不用初始化了,仅仅须要简单的get或者create即可了。
     2、耦合性低,工厂模式是典型的解耦框架。屏蔽了详细产品类(都是用产品接口嘛),调用者无需关心底层怎样实现,产品类变化时仅仅要接口不变就不影响调用者,使client和详细产品解耦,更能屏蔽创建详细产品时须要的其它关联类(如做饭就不须要依赖锯了),符合迪米特法则。仅仅和须要的类交流。也符合依赖导致原则,仅仅依赖抽象。更符合里氏替换原则。使用产品子类取代父类。全然没问题。
     3、扩展很方便,新加一类产品时(如上面样例新增一种button),仅仅须要新增一个工厂实现类就可以。无需改动原有代码,达到了“拥抱变化”,符合开闭原则。
     当产品创建简单,比較固定的时候。或者调用者个性化情况太多时,工厂就体现不出他的优势了,比方经常使用的List,我们就不是必需弄个ListFactory.createArrayList()。徒增代码复杂性。

还有种类比較固定。不会太多,不是必需抽象出接口,那也不必非用工厂模式。最好在以下的情况下才考虑使用工厂模式:

     1、调用者不须要直到详细的产品创建过程时;
     2、调用者使用的对象存在变动的可能,甚至全然不知道使用哪个详细对象时。

     3、须要做出灵活、可扩展的功能时。再考虑工厂模式。事实上不一定全部功能都要做到可扩展。慎重过度设计。

     4、须要解耦时,降低调用者和详细实现类的依赖时。
4、演示样例和扩展
     1、退化成简单工厂模式,当要创建的产品种类较少时,而且能够预见时,能够把工厂实现类合并到一起,对外提供一个静态工厂方法。比方上面的button样例中:
public static IButton crateButton(String type, String text) {        IButton btn = null;        if ("round".equals(type)) {            btn = new RoundButton(); // 圆形button        } else if ("rec".equals(type)) {            btn = new RecButton(); // 矩形button        } else {            return null ;        }        btn.setText(text);        btn.setBackgroundColor("#00aaff");        return btn;    }
       
这样的简单工厂模式用起来很easy。缺点是扩展困难,不符合开闭原则,要注意设计没有最好,仅仅有适不适合,在可预见的变化下,简单工厂模式很好用。
     2、
约束产品类实例数量,通常和其它模式组合能达到非常多效果,比方使用工厂创建好对象后缓存起来,达到单例或多例的目的。比方以下单例工厂:
//单例工厂public class SingletonFactory {    private static Map

>, Object> objCache = new HashMap<Class<?>, Object>(); public synchronized static Object getInstance(Class<?> clazz) throws Exception { Object singleton = objCache.get(clazz); if (singleton == null) { singleton = createInstance(clazz); objCache.put(clazz, singleton); } return singleton; } private static Object createInstance(Class<?> clazz) throws Exception { Constructor ct = clazz.getDeclaredConstructor(); ct.setAccessible( true); return ct.newInstance(); } }

     
3、多工厂协调,工厂模式中。一个工厂创建一个产品也行。创建多个产品也行。当产品种类过多时,假设工厂类也较多,此时最好弄一个协调类来协调,方便调用者使用。而不是让调用者逐个去找工厂类。

     单例
能够。多例也就没问题了,比方数据库连接池。设置最大100个,使用工厂模式就非常有效,此时须要考虑每一个实例的状态。使用中的话不能被获取等等。
     4、延迟实例化,有的时候产品创建和销毁比較耗费资源,能够考虑创建好之后缓存起来,用完之后不销毁,或者使用完成后将对象改成初始状态,而不是又一次创建,方便兴许使用,还是连接池的样例。假设用完了,是不销毁的,还会又一次使用。
     5、结合反射或配置文件,取代程序new。尽管样例中我们使用的是new创建对象,可是在现实编程中,大部分工厂都是配合反射来使用的,能够考虑将要创建的产品属性,设置工厂属性放到配置文件里,程序启动就将对象创建好。这样当添加一个简单产品时。能够做到改动配置文件即可,就算添加复杂产品,仅仅须要新写一个工厂类,配置配置即可。而不用大量改动源代码。
     结束语,工厂方法事实上在项目中使用很很频繁,这个模式差点儿人尽皆知,但却不是每一个人都能用好,工厂模式通常和其它模式混合使用,变化出无穷的优秀设计。

你可能感兴趣的文章
snownlp 中文语法分析
查看>>
Python中os和shutil模块实用方法集锦
查看>>
c++中的左值与右值
查看>>
阿里云推出免费套餐 30余款云产品半年免费
查看>>
linux 用户/用户组添加修改删除(ubuntu/centos)
查看>>
Flink 原理与实现:Window 机制
查看>>
Kubernetes环境下的各种调试方法
查看>>
CC2530之Flash笔记
查看>>
Weex Workshop 挑战赛,等你来战!
查看>>
linux 怎么完全卸载mysql数据库
查看>>
Dart的HTTP请求和响应(1)
查看>>
寻找最大的K个数,Top K问题的堆实现
查看>>
自动发布工具应该具备的11个标准特征
查看>>
页面设计四大基本原则
查看>>
2016及以后的自动化测试趋势 -《测试技术六月刊》
查看>>
基于Angular创建后台数据模拟(译)
查看>>
Spring中bean配置的继承
查看>>
用JSP实现学生查询
查看>>
企业网站怎么建设
查看>>
数据库和MySQL相关面试题目
查看>>