最近闲来无事了解了一下设计模式,得知最基本的设计模式就是工厂模式,然而从网上找了大堆的文章却总感觉不得要领,似乎很多大神级人物都不屑于讲这么“简单”的东西,因为当前业内人们似乎只对“高大上”的东西感兴趣,却很少有人注重最最基础的东西,今天把我对工厂模式这种最“简单”的设计模式做一下总结,如有不对欢迎指正。
1、普通工厂模式
描述:如果你有一个接口,想new一个实现类的对象,不要直接new,而是通过另外一个类来获得这个对象,另外的这个类就叫工厂类。代码举例(假设有A和B两个同事合作完成这个工程):
// 同事A的代码
/** 定义一个“移动电话”接口 */
public interface MobilePhone {
public void call(String phoneNumber);
}
/** 主程序中调用 */
public class MyTest {
private MobilePhone androidPhone;
private MobilePhone iPhone;
private MobilePhone windowsPhone;
public static void main(String[] args) {
// 等同事B写完工厂类再把下面三行创建对象的代码加进来
// 通过传参来创建对象,参数一定不能写错
androidPhone = PhoneFactory.createMobilePhone("Android");
iPhone = PhoneFactory.createMobilePhone("iPhone");
windowsPhone = PhoneFactory.createMobilePhone("Windows");
if (androidPhone != null) androidPhone.call("13900000000");
if (iPhone != null) iPhone.call("13900000000");
if (windowsPhone != null) windowsPhone.call("13900000000");
}
}
// 同事B的代码
/** 创建工厂类 */
public class PhoneFactory {
public static MobilePhone createMobilePhone(String phoneKind) {
if (phoneKind.equalsIgnoreCase("Android")) {
return new AndroidPhone();
} else if (phoneKind.equalsIgnoreCase("iPhone")) {
return new IPhone();
} else if (phoneKind.equalsIgnoreCase("Windows")) {
return new WindowsPhone();
}
return null;
}
}
/** 手机的实现类 */
public class AndroidPhone implements MobilePhone {
public void call(String phoneNumber) {
System.out.println("Dial phoneNumber " + phoneNumber + "use AndroidPhone");
}
}
public class IPhone implements MobilePhone {
public void call(String phoneNumber) {
System.out.println("Dial phoneNumber " + phoneNumber + "use iPhone");
}
}
public class WindowsPhone implements MobilePhone {
public void call(String phoneNumber) {
System.out.println("Dial phoneNumber " + phoneNumber + "use WindowsPhone");
}
}
作用:如果你跟另外一个同事合作写代码,你负责调用MobilePhone接口中的方法,他负责写MobilePhone实现类,就可以考虑用工厂模式,当有一天你的那个同事想改一成另外一个实现类,他不用通知你,只需要新写一个实现类再改一下工厂类就可以了。
缺点:你要等你同事写好工厂类之后再开始开发,没有做到解耦。
2、工厂方法模式
描述:前边讲的简单工厂模式是你通过传参告诉工厂类你想要什么产品,工厂类帮你生产,因为这个工厂可以生产很多种产品。
而工厂方法模式是:有很多工厂,每个工厂只能生产单一的一种产品,你想要哪种产品,就直接去找生产那种产品的工厂就好,不用传参了。
当然这一大堆工厂有一个统一的工厂接口,这一大堆产品也有一个统一的产品接口。
代码举例:
// 同事A的代码
/** 定义一个“移动电话”接口 */
public interface MobilePhone {
public void call(String phoneNumber);
}
/** 创建工厂类接口 */
public interface PhoneFactory {
public static MobilePhone createMobilePhone();
}
/** 主程序中调用 */
public class MyTest {
private MobilePhone androidPhone;
private MobilePhone iPhone;
private MobilePhone windowsPhone;
// 要创建多个工厂对象
private PhoneFactory androidPhoneFactory;
private PhoneFactory iPhoneFactory;
private PhoneFactory windowsPhoneFactory;
public static void main(String[] args) {
// 等同事B写完工厂类再把下面几行创建对象的代码加进来
androidPhoneFactory = new AndroidPhoneFactory();
iPhoneFactory = new IPhoneFactory();
windowsPhoneFactory = new WindowsPhoneFactory();
// 现在就不用传参了
androidPhone = androidPhoneFactory.createMobilePhone();
iPhone = iPhoneFactory.createMobilePhone();
windowsPhone = windowsPhoneFactory.createMobilePhone();
if (androidPhone != null) androidPhone.call("13900000000");
if (iPhone != null) iPhone.call("13900000000");
if (windowsPhone != null) windowsPhone.call("13900000000");
}
}
// 同事B的代码
/** 创建工厂类的实现类 */
public class AndroidPhoneFactory implements PhoneFactory {
public MobilePhone createMobilePhone() {
return new AndroidPhone();
}
}
public IPhoneFactory implements PhoneFactory {
public static MobilePhone createMobilePhone() {
return new IPhone();
}
}
public WindowsPhoneFactory implements PhoneFactory {
public static MobilePhone createMobilePhone() {
return new WindowsPhone();
}
}
/** 手机的实现类 */
public class AndroidPhone implements MobilePhone {
public void call(String phoneNumber) {
System.out.println("Dial phoneNumber " + phoneNumber + "use AndroidPhone");
}
}
public class IPhone implements MobilePhone {
public void call(String phoneNumber) {
System.out.println("Dial phoneNumber " + phoneNumber + "use iPhone");
}
}
public class WindowsPhone implements MobilePhone {
public void call(String phoneNumber) {
System.out.println("Dial phoneNumber " + phoneNumber + "use WindowsPhone");
}
}
作用:不用像普通工厂模式那样总要通过传参来告诉工厂类我要什么产品了,万一参数写错一个字母呢?是吧,现在需要哪种产品就直接找生产那种产品的工厂即可。
3、抽象工厂模式
描述:前边讲的工厂方法模式是有多个工厂,每个工厂只生产一种产品。而抽象工厂模式是有一个工厂接口,但是这工厂不止能生产一种产品,而是能生产多个产品。
作用:如果只是从抽象工厂模式自身出发来解释还是比难理解的,要了解抽象工厂模式其实最好是跟前边两种对比,你就会明白为什么要使用抽象工厂模式了。
(1)最开始的简单工厂模式的缺点是你总要通过传参来创建对象,传参有点麻烦,参数也有可能传错;
(2)工厂方法模式的缺点是你要先定义一大堆工厂接口的对象,用每个工厂接口对象创建一种产品,那么定义一大堆对象,然后去管理这一大堆对象显然也是比较麻烦的事情;
(3)如果我即不想通过传参创建对象,又不想创建一大堆工厂对象要怎么做呢?并且这个工厂在其它同事还没有做出来时先以接口形式存在,让我们可以提前使用、并且将来可以随意替换它的实现类呢?抽象工厂模式就是针对这一点对工厂方法模式做了改进。
// 同事A的代码
/** 定义一个“移动电话”接口 */
public interface MobilePhone {
public void call(String phoneNumber);
}
/** 创建工厂类接口 */
public interface PhoneFactory {
public static MobilePhone createAndroidPhone();
public static MobilePhone createIPhone();
public static MobilePhone createWindowsPhone();
}
/** 主程序中调用 */
public class MyTest {
private MobilePhone androidPhone;
private MobilePhone iPhone;
private MobilePhone windowsPhone;
// 现在只需要创建一个工厂对象
private PhoneFactory phoneFactory;
public static void main(String[] args) {
// 将来需求改变时可以随意替换工厂类的实现类,其它代码不用改
phoneFactory = new phoneFactoryImpl();
// 不需要传参就能创建对象
androidPhone = phoneFactory.createAndroidPhone();
iPhone = phoneFactory.createIPhone();
windowsPhone = phoneFactory.createWindowsPhone();
if (androidPhone != null) androidPhone.call("13900000000");
if (iPhone != null) iPhone.call("13900000000");
if (windowsPhone != null) windowsPhone.call("13900000000");
}
}
// 同事B的代码
/** 创建工厂类的实现类 */
public class PhoneFactoryImpl implements PhoneFactory {
public static MobilePhone createAndroidPhone() {
return new AndroidPhone();
}
public static MobilePhone createIPhone() {
return new IPhone();
}
public static MobilePhone createWindowsPhone() {
return new WindowsPhone();
}
}
/** 手机的实现类 */
public class AndroidPhone implements MobilePhone {
public void call(String phoneNumber) {
System.out.println("Dial phoneNumber " + phoneNumber + "use AndroidPhone");
}
}
public class IPhone implements MobilePhone {
public void call(String phoneNumber) {
System.out.println("Dial phoneNumber " + phoneNumber + "use iPhone");
}
}
public class WindowsPhone implements MobilePhone {
public void call(String phoneNumber) {
System.out.println("Dial phoneNumber " + phoneNumber + "use WindowsPhone");
}
}
缺点:等你的同事写好工厂类接口的实现类之后,你还是要回过头来改你当初的代码,把他的实现类赋给你的接口,也就是说还是无法实现完全的解耦。