9.9 接口与工厂

接口是实现多重继承的途径,而生成遵循某个接口的对象的典型方式就是工厂方法设计模式。这与直接调用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成解耦的某个实现的对象。理论上,通过这种方式,我们的代码将完全与接口的实现分离,这就使得我们可以透明地将某个实现替换为另一种实现。下面的实例展示了工厂方法的结构:
//: 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类表示一段复杂的代码,那么这种方式就允许你在不同类型的游戏中复用这段代码。

“确定接口是理想选择,因而应该总是选择接口而不是具体的类。”这其实是一种引诱。

任何抽象性都应该是应真正的需求而产生的。当必须时,你应该重构接口而不是导出添加额外级别的间接性,并由此带来的额外的复杂性。

恰当的原则应该是有限选择类而不是接口。从类开始,如果接口的必须行变得非常明确,那么就进行重构。