作为一个程序员,设计模式必须掌握,不管是日常开发,还是面试都会涉及到。我对设计模式的理解有时候只停留在了理论概念上,实战项目总感觉写不出来,代码不够优雅,所以,从今天开始,一天学习一个设计模式,并把相似的容易混淆的设计模式做出对比,加深对设计模式的理解。
之前看设计模式,总是不去看UML,我发现,这个东西才是真正能看懂掌握设计模式的根基,就好比一剂良药,需要有个药引子才能发挥出药效,必须先能看懂UML再学习设计模式,这样会事半功倍。
1、简单工厂模式(后续都以生产冰淇淋为例子)
UML,图上标注的序号,是类创建的步骤,我感觉这么写,能好理解一点
第一次,我先把每一个步骤都描述一下
- 创建接口 IceCreamService,定义方法 createIceCream(params)
- 创建2个实现类,AppleIceCreamServiceImpl、BananaIceCreamServiceImpl
- 创建工厂类 IceCreamFactory(params) ,定义方法getIceCreamService(params) 根据入参,返回需要生产的冰淇淋产品
下面是代码演示:
/**
* 1、冰淇淋接口
*/
public interface IiceCream {
void createIceCream();
}
/**
* 2、苹果冰淇淋实现类
*/
public class AppleIceCream implements IiceCream {
@Override
public void createIceCream() {
System.out.println("苹果冰淇淋");
}
}
/**
* 3、香蕉冰淇淋实现类
*/
public class BananaIceCreamServiceImpl implements IceCreamService{
@Override
public void createIceCream() {
System.out.println("香蕉冰淇淋");
}
}
/**
* 4、冰淇淋工厂类
*/
public class IceCreamFactory {
public IiceCream getIceCream(String params) {
switch (params) {
case "apple":
return new AppleIceCream();
case "banana":
return new BananaIceCream();
default:
return null;
}
}
public static void main(String[] args) {
IceCreamFactory icf = new IceCreamFactory();
// 生产苹果冰淇淋
icf.getIceCream("apple").createIceCream();
// 生产香蕉冰淇淋
icf.getIceCream("banana").createIceCream();
}
}
好了,简单工厂就完成了,很简单
2、工厂方法模式
上面的简单工厂方法有个弊端,如果要再新加别的冰淇淋,必须要去修改工厂类,这违反了设计原则-开闭原则。
怎么规避这个弊端呢?工厂方法模式闪亮登场
UML
代码演示:
/**
* 1、冰淇淋接口
*/
public interface IiceCream {
void createIceCream();
}
/**
* 2、苹果冰淇淋实现类
*/
public class AppleIceCream implements IiceCream {
@Override
public void createIceCream() {
System.out.println("苹果冰淇淋");
}
}
/**
* 3、香蕉冰淇淋实现类
*/
public class BananaIceCream implements IiceCream {
@Override
public void createIceCream() {
System.out.println("香蕉冰淇淋");
}
}
/**
* 4、冰淇淋工厂接口
*/
public interface IiceCreamFactory {
IiceCream getIceCream();
}
/**
* 5、苹果冰淇淋工厂实现类
*/
public class AppleFactory implements IiceCreamFactory {
@Override
public IiceCream getIceCream() {
return new AppleIceCream();
}
}
/**
* 6、香蕉冰淇淋工厂实现类
*/
public class BananaFactory implements IiceCreamFactory {
@Override
public IiceCream getIceCream() {
return new BananaIceCream();
}
}
/**
* 生产冰淇淋
*/
public class CreateIceCream {
public static void main(String[] args) {
// 苹果冰淇淋工厂
IiceCreamFactory appleFactory = new AppleFactory();
// 生产冰淇淋
appleFactory.getIceCream().createIceCream();
// 香蕉冰淇淋工厂
IiceCreamFactory bananaFactory = new BananaFactory();
// 生产冰淇淋
bananaFactory.getIceCream().createIceCream();
}
}
工厂方法模式完成,如果再新增一个橘子冰淇淋,分别创建一个工厂实现类,和冰淇淋实现类即可
3、抽象工厂模式
工厂方法模式已经可以完成大部分的需求,但是突然产品又提出了一个需求,现在不仅要生产冰淇淋,还要生产饮料,这时候,工厂方法模式可能有点扛不住了,因为工厂方法模式一个工厂只能生成一种产品。这时候抽象工厂模式炫丽登场
UML,是根据我自己的理解画的,跟网上大神的图不太一样,如有不正确的地方,大家指正,不过我觉得这么画更好理解
在画这个UML的时候,纠结了一会,从简单工厂到工厂方法,很容易理解,但是从工厂方法到抽象工厂,总感觉有点别扭。
:工厂方法到抽象工厂,正常的思路是,就是把冰淇淋工厂(IceCreamFactory)改造成,可以生产饮料不就行了?但是从实际想一下,真的有个冰淇淋工厂,那这个厂子里面的设备肯定不支持生产饮料的,两个完全不同的食品。
所以,如果想要生产冰淇淋,又要生产饮料,那你就不能再用冰淇淋工厂了,要用一个更大点的工厂,里面融合了生产冰淇淋和饮料的设备,可以同时生产这2种产品,比如说蒙牛,伊利这种大工厂
代码演示:
/**
* 1、冰淇淋接口
*/
public interface IceCream {
void createIceCream();
}
/**
* 2、苹果冰淇淋
*/
public class AppleIceCream implements IceCream {
@Override
public void createIceCream() {
System.out.println("苹果冰淇淋 ");
}
}
/**
* 3、香蕉冰淇淋
*/
public class BananaIceCream implements IceCream {
@Override
public void createIceCream() {
System.out.println("香蕉冰淇淋 ");
}
}
/**
* 4、饮料接口
*/
public interface Drinks {
void createDrinks();
}
/**
* 5、苹果饮料
*/
public class AppleDrinks implements Drinks {
@Override
public void createDrinks() {
System.out.println("苹果饮料");
}
}
/**
* 6、香蕉饮料
*/
public class BananaDrinks implements Drinks {
@Override
public void createDrinks() {
System.out.println("香蕉饮料");
}
}
/**
* 7、抽象工厂接口,生产冰淇淋和饮料
*/
public interface AbstractFactory {
// 冰淇淋
IceCream createIceCream(String choice);
// 饮料
Drinks createDrinks(String choice);
}
/**
* 8、蒙牛工厂
*/
public class MengNiuFactory implements AbstractFactory {
@Override
public IceCream createIceCream(String choice) {
switch (choice) {
case "banana":
return new BananaIceCream();
case "apple":
return new AppleIceCream();
default:
return null;
}
}
@Override
public Drinks createDrinks(String choice) {
switch (choice) {
case "banana":
return new BananaDrinks();
case "apple":
return new AppleDrinks();
default:
return null;
}
}
}
/**
* 9、伊利工厂
*/
public class YiLiFactory implements AbstractFactory {
@Override
public IceCream createIceCream(String choice) {
switch (choice) {
case "banana":
return new BananaIceCream();
case "apple":
return new AppleIceCream();
default:
return null;
}
}
@Override
public Drinks createDrinks(String choice) {
switch (choice) {
case "banana":
return new BananaDrinks();
case "apple":
return new AppleDrinks();
default:
return null;
}
}
}
/**
* 制造产品
*/
public class MakeProduct {
public static void main(String[] args) {
AbstractFactory yiLi = new YiLiFactory();
System.out.println("伊利工厂生产");
yiLi.createIceCream("apple").createIceCream();
yiLi.createDrinks("banana").createDrinks();
AbstractFactory mengNiu = new MengNiuFactory();
System.out.println("蒙牛工厂生产");
mengNiu.createIceCream("apple").createIceCream();
mengNiu.createDrinks("banana").createDrinks();
}
}
在实际的项目中,要根据需求选择合适的设计模式,但凡你用了一些设计模式,别人再看到你写的代码,都会对你高看一眼,我就这么觉得,看到别人把设计模式实战到项目中,就会觉得这个人厉害,内功深厚。
再补充一点,看了一些关于设计模式的书,解决了我的一个误区,设计模式并不是用得越多,或者说用法越复杂就越好,设计模式的初衷就是简化我们开发过程中遇到的一些困难,就好比上面的三种工厂模式,并不是说抽象工厂模式(复杂度高)最好,合适的场景,用适合的设计模式,才最好。
所以,不能为了设计模式而设计模式,用的时候需要思考为什么我要用这个设计模式,用了之后会给我们的代码带来什么好处,都是要思考的。