接口是实现多重继承的途径,而生成遵循某个接口的对象的典型方式就是工厂方法设计模式。这与直接调用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成解耦的某个实现的对象。理论上,通过这种方式,我们的代码将完全与接口的实现分离,这就使得我们可以透明地将某个实现替换为另一种实现。下面的实例展示了工厂方法的结构:
//: interfaces/Factories.java
interface Service {
void method1();
void method2();
}
interface ServiceFactory {
Service getService();
}
class Implementation1 implements Service {
implementation1() {} // Package access
public void method1() {
System.out.print("Implementation1 method1");
}
public void method2() {
System.out.print("Implementation1 method2");
}
}
class Implementation2 implements Service {
implementation2() {} // Package access
public void method1() {
System.out.print("Implementation2 method1");
}
public void method2() {
System.out.print("Implementation2 method2");
}
}
class Implementation2Factory implemnts ServiceFactory {
public service getService() {
return new Implementation2();
}
}
public class Factories {
public static void serviceConsumer(ServiceFactory fact){
serviceConsumer(new Implementation1Factory());
// Implementations are completely interchangeable;
serviceConsumer(new Implementation2Factory());
}
}/* Output:
Implementation1 method1
Implementation1 method2
Implementation2 method1
Implementation2 method2
*///:~
如果不是工厂方法,你的代码就必须在某处制定将要创建的Service的确切类型,以便调用合适的构造器。
为什么我们想要添加这种额外级别的间接性呢?一个常见的原因是想要创建框架:加入你正在创建一个博弈游戏系统,例如,在相同的棋盘上下国际象棋和西洋跳棋:
//:interfaces/Games.java
// A Game framework using Factory Methods
package July_9;
interface Game {boolean move();}
interface GameFactory{Game getGame();}
class Checkers implements Game {
private int moves = 0;
private static final int MOVES = 3;
public boolean move() {
System.out.println("Checkers move" + moves);
return ++moves != MOVES;
}
}
class CheckersFactory implements GameFactory {
public Game getGame() {
return new Checkers();
}
}
class Chess implements Game {
private int moves = 0;
private static final int MOVES = 4;
public boolean move() {
System.out.println("Chess move " + moves);
return ++moves!= MOVES;
}
}
class ChessFactory implements GameFactory{
public Game getGame(){return new Chess();}
}
public class Games {
public static void playGame(GameFactory factory){
Game s = factory.getGame();
while (s.move());
}
public static void main(String[] args) {
playGame(new CheckersFactory());
playGame(new ChessFactory());
}
}/* Output:
Checkers move0
Checkers move1
Checkers move2
Chess move 0
Chess move 1
Chess move 2
Chess move 3
*///:~
如果Games类表示一段复杂的代码,那么这种方式就允许你在不同类型的游戏中复用这段代码。
“确定接口是理想选择,因而应该总是选择接口而不是具体的类。”这其实是一种引诱。
任何抽象性都应该是应真正的需求而产生的。当必须时,你应该重构接口而不是导出添加额外级别的间接性,并由此带来的额外的复杂性。
恰当的原则应该是有限选择类而不是接口。从类开始,如果接口的必须行变得非常明确,那么就进行重构。