设计模式之工厂模式

        从一个例子开始介绍工厂模式。

        假设有一个生产Windows系统兼容机和Mac电脑的工厂,里面有一个装配员,当客户需要一台电脑时,告诉装配员是需要Windows系统电脑还是Mac系统电脑,工厂就会生产一台电脑并且交由装配员装配,然后交给客户。

首先需要一个电脑的接口:

public interface Computer {
	public void selfIntroduce(); // 打印电脑信息
}
Windows电脑的实现类:

public class Windows implements Computer {

	@Override
	public void selfIntroduce() {
		System.out.println("Windows已生产.");
	}

}
Mac电脑的实现类:
public class Mac implements Computer {

	@Override
	public void selfIntroduce() {
		System.out.println("Mac已生产.");
	}

}
装配员实现类:

public class Boxer {
	public Computer boxComputer(String computer) {
		if(computer.equals("Mac")) {
			return new Mac();
		} else {
			return new Windows();
		}
	}
	
}
测试类:

public class Main {

	public static void main(String[] args) {
		Boxer boxer = new Boxer();
		Computer computer1 = boxer.boxComputer("Mac"); // 客户要求生产一台Mac系统电脑
		computer1.selfIntroduce();
		Computer computer2 = boxer.boxComputer("Windows"); // 客户要求生产一台Windows系统电脑
		computer2.selfIntroduce();
	}

}
可以看到输出:

Mac已生产.

Windows已生产.

这就是简单工厂模式,客户希望得到哪台类型的电脑,只需要告诉装配员,工厂就会生产一台对应的电脑出来,用法很简单。但是简单工厂模式不符合开闭原则(对扩展开放,对修改关闭),当用户希望得到一台linux电脑时,需要增加Linux电脑实现类:

public class Linux implements Computer {

	@Override
	public void selfIntroduce() {
		System.out.println("Linux已生产.");
	}

}
再增加装配员的功能:

public class Boxer {
	public Computer boxComputer(String computer) {
		if(computer.equals("Mac")) {
			return new Mac();
		} else if(computer.equals("Linux")) {
			return new Linux();
		} else {
			return new Windows();
		}
	}
	
}
测试:

public class Main {

	public static void main(String[] args) {
		Boxer boxer = new Boxer();
		Computer computer1 = boxer.boxComputer("Mac");
		computer1.selfIntroduce();
		Computer computer2 = boxer.boxComputer("Windows");
		computer2.selfIntroduce();
		Computer computer3 = boxer.boxComputer("Linux"); // 客户要求再生产一台Linux系统电脑
		computer3.selfIntroduce();
	}

}
输出:

Mac已生产.

Windows已生产.

Linux已生产.

如果还有更多系统类型的电脑,如Ubuntu、RedHat、朝鲜的红星,如果再细一点,Windows需要生产Win98、Win7、Win10等等,这样,需要装配员实现类代码会急剧增加,严重违反开闭原则。如果继续采用上面的方式,整个需求的实现将是个噩梦。

要实现用户的新需求,整个工厂方法应该如何来写呢?

这里,我们采用抽象工厂模式。

抽象工厂模式与简单工厂模式最大的区别在于,抽象工厂模式将产生产品类和角色类,同一个系列的产品将由对应的产品类和角色类组成的工厂来生产,也就是说抽象工厂模式是由许多个工厂流水线组成。假如客户需要Windows系统电脑,工厂j就会交由Windows装配员来完成并将产品交给客户,这就是抽象工厂模式。

开始完成客户的新需求:

装配员的接口:

public interface Boxer {
	public Computer assembledComputer();
}
Windows电脑装配员实现类:

public class WindowsBoxer implements Boxer {

	@Override
	public Computer assembledComputer() {
		return new Windows();
	}

}
Mac电脑装配员实现类:

public class MacBoxer implements Boxer {

	@Override
	public Computer assembledComputer() {
		return new Mac();
	}

}
Linux电脑装配员实现类:
public class LinuxBoxer implements Boxer {

	@Override
	public Computer assembledComputer() {
		return new Linux();
	}

}
测试:

public class Main {

	public static void main(String[] args) {
		Boxer boxer1 = new WindowsBoxer();
		Computer computer1 = boxer1.assembledComputer();
		computer1.selfIntroduce();
		Boxer boxer2 = new MacBoxer();
		Computer computer2 = boxer2.assembledComputer();
		computer2.selfIntroduce();
		Boxer boxer3 = new LinuxBoxer();
		Computer computer3 = boxer3.assembledComputer();
		computer3.selfIntroduce();
	}

}
输出:

Windows已生产.

Mac已生产.

Linux已生产.

可以看到,采用抽象工厂模式后,整个需求实现的代码量增大了,但是结构上更加清晰,并且符合开闭原则。

假如客户又有新的需求,需要的电脑包装里面装好电源适配器,那我们可以继续用抽象工厂模式的方式来扩展。

增加电源适配器接口:

public interface Adapter {
	public void assembled();
}
Windows电源适配器实现类:

public class WindowsAdapter implements Adapter {
	
	@Override
	public void assembled() {
		System.out.println("Windows电源适配器已装配.");
	}

}
Mac和Linux电源适配器同理,此处略。

修改Windows实现类:

public class Windows implements Computer {
	private Adapter windowsAdapter;
	public Windows(Adapter windowsAdapter) {
		this.windowsAdapter = windowsAdapter;
	}
	@Override
	public void selfIntroduce() {
		System.out.println("Windows已生产.");
		windowsAdapter.assembled();
	}

}
同理修改Mac和Linux实现类。

测试:

public class Main {

	public static void main(String[] args) {
		Boxer boxer1 = new WindowsBoxer();
		Computer computer1 = boxer1.assembledComputer();
		computer1.selfIntroduce();
		Boxer boxer2 = new MacBoxer();
		Computer computer2 = boxer2.assembledComputer();
		computer2.selfIntroduce();
		Boxer boxer3 = new LinuxBoxer();
		Computer computer3 = boxer3.assembledComputer();
		computer3.selfIntroduce();
	}

}

输出:

Windows已生产.

Windows电源适配器已装配.

Mac已生产.

Mac电源适配器已装配.

Linux已生产.

Linux电源适配器已装配.

新的需求将抽象工厂类的产品和对应角色组装在了一起,也可以理解为工厂里面包含一个小的工厂,具体的产品交由小的工厂来实现,这样在产品和角色比较多的场合是非常适合的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值