设计模式之简单工厂/工厂方法/抽象工厂

这三个设计模式都属于创建型模式,之间具有关联性,就放在一起讲解。其实简单工厂模式是工厂方法的一个特例,并不是23种设计模式的一种。

使用java来写的这几个设计模式。java文件目录树如下所示:

zy@zy:~/code/designpattern/SimpleFactory/src$ tree
.
├── Client.java
└── zy
    ├── abstractfactory
    │   ├── AccerFactory.java
    │   ├── AppleFactory.java
    │   └── ComputerAbstractFactoy.java
    ├── factory
    │   ├── ComputerFactory.java
    │   ├── DesktopComputerFactory.java
    │   └── LaptopFactory.java
    ├── product
    │   ├── AccerDesktopComputer.java
    │   ├── AccerLaptop.java
    │   ├── AppleDesktopComputer.java
    │   ├── AppleLaptop.java
    │   ├── Computer.java
    │   ├── DesktopComputer.java
    │   └── Laptop.java
    └── simplefactory
        └── ComputerSimpleFactory.java

5 directories, 15 files

通过一个教研室购买电脑的场景来描述动机和相应的优缺点。

一个教研室会购买一定数量的电脑来让学生干活,比较早些的时候购买的是台式机,

1. 下面看看普通的创建方法。

//Computer.java
package zy.product;

public interface Computer {
	void uname();
}

//Laptop.java
package zy.product;

public class Laptop implements Computer {
	public void uname()
	{
		System.out.println("我是笔记本,更加便于携带");
	}

}


//DesktopComputer.java
package zy.product;

public class DesktopComputer implements Computer {
	public void uname()
	{
		System.out.println("我是台式机,屏幕更大");
	}

}

//一般调用的测试方法
	public static void normalTest() {
		Computer labComputer1 = new Laptop();
		labComputer1.uname();
		Computer labComputer2 = new Laptop();
		labComputer2.uname();
		Computer labComputer3 = new Laptop();
		labComputer3.uname();
		Computer labComputer4 = new Laptop();
		labComputer4.uname();
		Computer labComputer5 = new Laptop();
		labComputer5.uname();		
	}
这里,教研室需要5台笔记本,但是如果过两年,教研室需要5台台式机,那么就需要更改每一个创建对象的语句。这样的可读性和可维护性都不好。


2. 简单工厂模式

思路是通过一个简单的工厂来进行电脑的创建,让客户端直接调用工厂来得到电脑,从而自己不用管电脑是如何生产的。 看如下代码:

//ComputerSimpleFactory.java
package zy.simplefactory;

import zy.product.Computer;
import zy.product.DesktopComputer;
import zy.product.Laptop;

public class ComputerSimpleFactory {
	public static Computer createComputer(String computerName) {
		if( "Laptop".equals(computerName)) {
			return new Laptop();
		}
		else if( "DesktopComputer".equals(computerName)) {
			return new DesktopComputer();
		}
		else
			return new Laptop();
	}

}

//简单工厂的测试方法	
	public static void simpleFactoryTest() {
		//实验室要5台笔记本
		/*
		Computer labComputer1 = ComputerFactory.createComputer("Labtop"); 
		labComputer1.uname();
		Computer labComputer2 = ComputerFactory.createComputer("Labtop"); 
		labComputer2.uname();
		Computer labComputer3 = ComputerFactory.createComputer("Labtop"); 
		labComputer3.uname();
		Computer labComputer4 = ComputerFactory.createComputer("Labtop"); 
		labComputer4.uname();
		Computer labComputer5 = ComputerFactory.createComputer("Labtop"); 
		labComputer5.uname();
		*/
		
		//实验室更改需求,要5台台式机
		Computer labComputer1 = ComputerSimpleFactory.createComputer("DesktopComputer"); 
		labComputer1.uname();
		Computer labComputer2 = ComputerSimpleFactory.createComputer("DesktopComputer"); 
		labComputer2.uname();
		Computer labComputer3 = ComputerSimpleFactory.createComputer("DesktopComputer"); 
		labComputer3.uname();
		Computer labComputer4 = ComputerSimpleFactory.createComputer("DesktopComputer"); 
		labComputer4.uname();
		Computer labComputer5 = ComputerSimpleFactory.createComputer("DesktopComputer"); 
		labComputer5.uname();
	}
可以看到,直接调用工厂类的静态方法来生产笔记本就可以了。统一的接口可读性更好。并且便于维护。


3. 工厂方法模式

上面的简单工厂模式,有个缺点就是如果增加了一种电脑的种类,比如超极本。 就需要修改工厂的静态生产方法,违背了开放-封闭原则,对修改也进行了开放。

针对这个缺点,利用父类和子类之间虚函数的多态性,动态绑定,可以方便的创建对象。代码如下:

//ComputerFactory.java
package zy.factory;

import zy.product.Computer;

public interface ComputerFactory {
	public Computer createComputer();

}

//LaptopFactory.java
package zy.factory;

import zy.product.Computer;
import zy.product.Laptop;

public class LaptopFactory implements ComputerFactory{
	public Computer createComputer() {
		return new Laptop();
	}
}

//DesktopComputerFactory.java
package zy.factory;

import zy.product.Computer;
import zy.product.DesktopComputer;

public class DesktopComputerFactory implements ComputerFactory{
	public Computer createComputer() {
		return new DesktopComputer();
	}
}

//工厂方法的测试方法	
	public static void factoryTest() {
		//原来需求
		ComputerFactory factory = new LaptopFactory();
		//需求更改:
		//ComputerFactory factory = new DesktopComputerFactory();
		Computer labComputer1 = factory.createComputer();
		labComputer1.uname();
		Computer labComputer2 = factory.createComputer();
		labComputer2.uname();
		Computer labComputer3 = factory.createComputer(); 
		labComputer3.uname();
		Computer labComputer4 = factory.createComputer();
		labComputer4.uname();
		Computer labComputer5 = factory.createComputer();
		labComputer5.uname();	
	}	

可以看到,如果增加了一个超极本的种类,不用修改现有的代码,直接增加一个超极本的工厂即可。并且客户端的需求代码,也只用更换一个工厂即可。 比简单工厂具有更好的可扩展性。 工厂方法模式,又叫做虚构造模式,就是通过这个方法来代替构造函数的作用。


4. 抽象工厂模式

教研室本来是用的宏碁牌子的电脑,但是现在变成土豪了,要更换成苹果的电脑。 如果使用工厂方法,就需要*2倍的建造工厂,代码量变大了许多。 这时候可以采取抽象工厂模式,将多个相关的工厂方法放在一个工厂里,比如将生产电脑(包括笔记本/台式机)的方法放在苹果厂里和宏碁厂里。这样减少了代码量。 把一些具体的相关产品抽象到了一个工厂里。

//AppleLaptop.java
package zy.product;

public class AppleLaptop extends Laptop{
	public void uname()
	{
		System.out.println("我是苹果笔记本,更加便于携带");
	}
}

//AppleDesktopComputer.java
package zy.product;

public class AppleDesktopComputer extends DesktopComputer{
	public void uname()
	{
		System.out.println("我是苹果台式机,屏幕更大");
	}
}

//AccerLaptop.java
package zy.product;

public class AccerLaptop extends Laptop {
	public void uname()
	{
		System.out.println("我是宏碁笔记本,更加方便携带");
	}
}

//AccerDesktopComputer.java
package zy.product;

public class AccerDesktopComputer extends DesktopComputer {
	public void uname()
	{
		System.out.println("我是宏碁台式机,屏幕更大");
	}
}


//ComputerAbstractFactoy.java
package zy.abstractfactory;

import zy.product.DesktopComputer;
import zy.product.Laptop;

public interface ComputerAbstractFactoy {
	public Laptop createLaptop();
	public DesktopComputer createDesktopComputer();

}

//AppleFactory.java
package zy.abstractfactory;

import zy.product.AppleDesktopComputer;
import zy.product.AppleLaptop;
import zy.product.DesktopComputer;
import zy.product.Laptop;

public class AppleFactory implements ComputerAbstractFactoy{
	public Laptop createLaptop() {
		return new AppleLaptop();
	}
	
	public DesktopComputer createDesktopComputer() {
		return new AppleDesktopComputer();
	}

}

//AccerFactory.java
package zy.abstractfactory;

import zy.product.AccerDesktopComputer;
import zy.product.AccerLaptop;

import zy.product.DesktopComputer;
import zy.product.Laptop;

public class AccerFactory implements ComputerAbstractFactoy{
	public Laptop createLaptop() {
		return new AccerLaptop();
	}
	
	public DesktopComputer createDesktopComputer() {
		return new AccerDesktopComputer();
	}

}


//抽象工厂的测试方法
	public static void abstratFactoryTest() {
		//原来需求,苹果的笔记本
		ComputerAbstractFactoy factory = new AppleFactory();
		//现在的需求,宏碁的笔记本
		//ComputerAbstractFactoy factory = new AccerFactory();
		Computer labComputer1 = factory.createLaptop();
		labComputer1.uname();
		Computer labComputer2 = factory.createLaptop();
		labComputer2.uname();
		Computer labComputer3 = factory.createLaptop(); 
		labComputer3.uname();
		Computer labComputer4 = factory.createLaptop();
		labComputer4.uname();
		Computer labComputer5 = factory.createLaptop();
		labComputer5.uname();
	}
可以看到抽象工厂具有比工厂方法更小的规模。 当需要更换一些列产品的时候,只需要更换一个工厂类即可。但是,如果新产品进来的时候,需要修改抽象工厂类的设计,同时修改现有的工厂类的代码。



注:

代码打包在:点击打开链接


你可能感兴趣的:(java,设计模式,工厂模式)