• 敏捷技能修炼之小舵板之二:分离构造和使用


    上一篇:敏捷技能修炼之小舵板之一:意图导向编程 http://zh.5long.me/2014/Agile-Development-Programming-by-Intention/

    前言

    软件开发从面向过程向面向对象发展的时候,给开发带来了不少好处,但同时也引出一个新的问题:实例化。比较常用的创建实例的做法是"哪里用到,就在哪里创建",但这也经常有负面效应。《敏捷技能修炼-敏捷软件开发与设计的最佳实践》一书中提出分离使用实例和构造实例。

    对象隐藏

    在一个老系统上添加新功能时,往往是非常复杂的,复杂之处不在于实现功能的复杂,而在于集成的复杂性,老系统耦合度高时更是如此。我们都知道面向对象中隐藏实现是非常重要的。但是,隐藏对象的类型也同样重要。也就是说,我们应该隐藏对象的具体类型,面向接口编程,使调用代码变得更简单,系统更易于维护。

    分离构造和使用的实例

    分离构造和使用就是要把对象的构造是使用分开,我们看下面这段代码:

    public class BusinessObject
    {
    	public void actioMethod()
    	{
    		//other things
    		Service myServiceObject = new Service()
    		myServiceObject.doService()
    		//other thing
    	}
    }
    

    这段代码中BusinessObject使用了Service的一个实例来实现某个功能,BusinessObject类是Service类的创建者,同时也是Service类的使用者。

    使用new就往往意味着无法使用重写(override),也就是说,使用 new Service()创建的对象就是Service的一个实例,不会是它的子类对象或其他类。

    假设某一天要修改代码,Service不再是一个类,而是一个接口了,有一个它的实现类是Service_Imp1,那么上面代码应该做如下修改:

    public class BusinessObject
    {
    	public void actioMethod()
    	{
    		//other things
    		Service myServiceObject = new Service_Imp1()  //此处有修改
    		myServiceObject.doService()
    		//other thing
    	}
    }
    

    如果有很多地方都使用new来创建实例,我们就不得不一一修改,代码已经产生了耦合性。

    对比上面两段代码,可以看出,只在创建实例的地方不同,如果把创建实例的方法分离出来,那情况就不一样了。我们使用下面一个类创建Service实例

    public class ServiceFactory
    {
    	public static Service getSevice()
    	{
    		return new Service()
    	}
    }
    

    那么上面第一段代码就可以改成如下代码

    public class BusinessObject
    {
    	public void actioMethod()
    	{
    		//other things
    		Service myServiceObject = ServiceFactory.getSevice();
    		myServiceObject.doService()
    		//other thing
    	}
    }
    

    Service改成接口是,我们只需修改ServiceFactory类

    public class ServiceFactory
    {
    	public static Service getSevice()
    	{
    		return new Service_Imp1()
    	}
    }
    

    不管有多少地方使用到实例,我们只需修改一处。更重要的是,假设还有一个Service的实现类Service_Imp2,系统根据不同条件来决定使用哪个类,那么ServiceFactory类就可做如下修改,而不用修改客户端代码

    public class ServiceFactory
    {
    	public static Service getSevice()
    	{
    		if (选择条件)
    		{
    			return new Service_Imp1()
    		}
    		else
    		{
    			return new Service_Imp2()
    		}
    	}
    }
    

    实际考虑

    这样看,隐藏确实给了我们很多好处,但使用一个单独的类来构造实例有时似乎过于奢侈,毕竟我写的类很多都不会有子类或一开始就使用接口,我们应该用最少的类来完成功能。书中推荐的另一种方法是我比较喜欢的,示例代码如下:

    public class BusinessObject
    {
    	public void actioMethod()
    	{
    		//other things
    		Service myServiceObject = Service.getInstance();
    		myServiceObject.doService()
    		//other thing
    	}
    }
    class Service
    {
    	private Service() { }
    	public static  Service getInstance()
    	{
    		return new Service();
    	}
    	public  void doService() { }
    }
    

    把构造方法放在Service类中,我们不需要额外写一个类来构造实例,同时也能得到ServiceFactory类来构造实例的好处。

    假如代码有需要修改成Service变成一个接口,两个实现类:Service_Imp1和Service_Imp2这种情况,可以轻而易举的重新设计构造方法:

    abstract class Service
    {
    	private Service() { }
    	public static  Service getInstance()
    	{
    		return ServiceFactory.getSevice();
    	}
    	abstract  void doService() { }
    }
    public class ServiceFactory
    {
    	public static Service getSevice()
    	{
    		if (选择条件)
    		{
    			return new Service_Imp1()
    		}
    		else
    		{
    			return new Service_Imp2()
    		}
    	}
    }
    

    分离构造和使用与单例模式

    单例模式是我们比较常用的一种设计模式,使用分离构造和使用就能额外的得到一个好处:类可方便的改成单例模式。还以Service类为例

    public class Service
    {
    	private Service() { }
    	public static  Service getInstance()
    	{
    		return new Service();
    	}
    	public  void doService() { }
    }
    

    假设系统修改了,Service要使用单例模式,整个系统的代码只需做如下修改:

    public class Service
    {
    	private static Service instance;
    	private Service() { }
    	public static  Service getInstance()
    	{
    		if (null == instance)
    		{
    			instance = new Service();
    		}
    		return instance;
    	}
    	public  void doService() { }
    }
    

    结语

    以上就是关于分离构造和使用的介绍,后续还会继续更新第三个小舵板。

    原文链接: http://zh.5long.me/2014/Agile-Development-separate-build-use/
    版权声明:自由转载-非商用-保持署名 | Creative Commons BY-NC 4.0

  • 相关阅读:
    IDL变量和数组使用
    IDL程序部署
    silverlight连接数据库的四种方法
    ENVI 5.0安装教程
    ArcGIS Server发布地图时提示打包失败解决方法
    ArcGIS Server服务未发布成功,怎么删除?
    Win8磁盘100% Win8磁盘占用100%解决办法终结版(3)
    攻防世界 reverse 进阶 -gametime
    攻防世界 reverse 进阶 16-zorropub
    攻防世界 reverse 进阶 15-Reversing-x64Elf-100
  • 原文地址:https://www.cnblogs.com/5long/p/4745338.html
Copyright © 2020-2023  润新知