OO设计中对象的创建和使用(二)

来源:互联网 发布:阿里云cname域名解析 编辑:程序博客网 时间:2024/04/27 23:33
实际工作中的观点

  这是否就意味着你的设计中的每一个类都应该有一个"工厂类",而其它类都必须实例化这个工厂类?当然,如果问题很简单,没什么变数,例如一个普通排序类,那就是杀鸡用牛刀了。

  但这就经常会有问题,我们永远不知道将来会发生什么样的变化。很不幸,我们预知变化的能力历来都不高。有一个折衷的办法是:把构造器封装在自己的类里面。

  只要简单地把构造器声明为private或是protected,然后添加一个静态方法,这静态方法返回一个实例。代码片段如下:

public class Sender{
 private Sender() {
  // do any constructor behavior here
 }
 public static Sender getInstance() {
  return new Sender();
 }
}
public class Client{
 private Sender mySender;
 public Client() {
  mySender = Sender.getInstance();
 }
}
  这里关键的不同在于,"封装了构造器",通常客户对象的代码是这样写的"mySender = Sender.getInstance();",而不是"mySender = new Sender();"。通过把构造器声明为private可以屏蔽后一种做法。

  初一看,这好象没有什么意义,和普通做的写法没有什么不同。但是,这样我们封装了"new"这个操作符。在C#或是JAVA这样语言中,"new"是不能被重载的,且我们不能控制它的返回类型,你通过"new"后面跟一个类名来指定一个类型,而它总是返回这个类型。而getInstance方法就不同了,它能返回其它类型作为返回值。当Sender需要做一点改变时,这种价值就很明显了。我们可以把Sender变成一种多态性服务。

public class Sender{
 private static Sender getInstance() {
  if (someDecisionLogic()){
   return new SenderImpl1();
  } else {
   return new SenderImpl2();
  }
 }
}

public class SenderImpl1 extends Sender {
 // one version of the Sender service
}

public class SenderImpl2 extends Sender {
 // another version of the Sender service
}

public class Client {
 private Sender mySender;
 public Client() {
  mySender = Sender.getInstance();
 }
}


  这里主要的好处就是,当变化来临的时候,客户对象不需要改变。当有很多客户对象使用这个服务时,这就更有价值了,因此出于将来的维护的考虑,这么作是非常有必要的。

  但是这好象违反了概念划分的原则吧?毕竟,这里Sender即是概念抽象(抽象类)同时又是具体实现(实现了工厂类)。是的,在眼前看来,我们有时要更实用主义一些,象这样允许一些不可预料的变化。而不是为了所有可能的变化放置一些不必要的代码在里面。

  在这个例子中,Sender的方法getInstance()作了一个简单的决策(决定那个子类被创建),并且可能一直都是这么简单。如果问题变复杂,我们将会分离出工厂类来负责创建Sender的子类。这是否意味着需要修改客户对象呢,把调用静态方法改为调整工厂类?完全不用,我们可以做一个这样的委托。

public abstract class Sender{
 private static SenderFactory myFactory = SenderFactory.getInstance();
 private static Sender getInstance() {
  return myFactory.getSender();
 }
}
}
public class Client {
 private Sender mySender;
 public Client() {
  mySender = Sender.getInstance();
 }
}
  当然,这是个不错的选择。如果客户对象很少,并且有些时间来重构,我们也可以把客户对象改为直接调用工厂类。但这并不是必要的,而且有点钻牛角尖了。你有没注意到,SenderFactory的构造器也被封装了,Sender调用静态方法getInstance来创建SenderFacroty实例。也许有一天工厂类也会变成多态性服务,所以,把它也封装起来会更好吧!

  另外,把工厂类做成Singleton(一种设计模式,它能保证一个类只有一个实例,并通过一个全局的访问点访问这个实例)是很常见的。在重构代码时,只需举手之劳就能把构造的过程封装成Singleton。