这三个设计模式都属于创建型模式,之间具有关联性,就放在一起讲解。其实简单工厂模式是工厂方法的一个特例,并不是23种设计模式的一种。
使用java来写的这几个设计模式。java文件目录树如下所示:
[email protected]:~/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(); }
可以看到抽象工厂具有比工厂方法更小的规模。 当需要更换一些列产品的时候,只需要更换一个工厂类即可。但是,如果新产品进来的时候,需要修改抽象工厂类的设计,同时修改现有的工厂类的代码。
注:
代码打包在:点击打开链接