设计模式(英语 design pattern)是对面向对象设计中反复出现的问题的解决方案,学习设计模式也是深入体会面向对象魅力的过程。设计模式大致分为23种,下面,我将介绍一些常用的设计模式。
工厂模式
工厂顾名思义就是创建产品,根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。该模式用于封装和管理对象的创建,是一种创建型模式。本文从一个具体的例子逐步深入分析,来体会三种工厂模式的应用场景和利弊。
不用工厂模式的代码是这样的
public class negtive {
/*===============服务端======================*/
interface Food{
void eat();
}
static class Hamburger implements Food {
@Override
public void eat() {
System.out.println("吃汉堡。。。。。");
}
}
static class Drumstick implements Food {
@Override
public void eat() {
System.out.println("吃鸡腿。。。。。");
}
}
static class Milk implements Food {
@Override
public void eat() {
System.out.println("喝牛奶。。。。。");
}
}
/*=================客户端===================*/
public static void main(String[] args) {
Food food01 = new Hamburger();
Food food02 = new Drumstick();
Food food03 = new Milk();
food01.eat();
food02.eat();
food03.eat();
}
}
此时客户端和服务器端高度耦合,如果服务器端作者突发奇想需要更改Noodles类名,那么客户端也必须一同更改,违反了迪米特法则。这样高度耦合的代码是不允许存在的,所以衍生出了工厂模式。
- 简单工厂模式
该模式对对象创建管理方式最为简单,服务器端将类封装在一起,外界使用服务器端提供的规则就可以创建对应的实例。
public class postive {
/*===============服务端======================*/
interface Food{
void eat();
}
static class Hamburger implements Food {
@Override
public void eat() {
System.out.println("吃汉堡。。。。。");
}
}
static class Drumstick implements Food {
@Override
public void eat() {
System.out.println("吃鸡腿。。。。。");
}
}
static class Milk implements Food {
@Override
public void eat() {
System.out.println("喝牛奶。。。。。");
}
}
static class FoodFactory {
public Food getFood(int num){
Food food =null;
switch (num){
case 1 :
food = new Hamburger();
case 2 :
food = new Drumstick();
case 3 :
food = new Milk();
}
return food;
}
}
/*=================客户端===================*/
public static void main(String[] args) {
FoodFactory foodFactory = new FoodFactory();
Food food01 = foodFactory.getFood(1);
Food food02 = foodFactory.getFood(2);
Food food03 = foodFactory.getFood(3);
food01.eat();
food02.eat();
food03.eat();
}
}
此时运用简单工厂模式便将服务端和客户端解耦,当服务端代码修改时,客户端也不需要知道具体该了些什么了。
当然缺点也显而易见
- 客户必须记住工厂中常量和具体产品的映射关系。
- 一旦产品品种体量增大到一定程度,工厂类将变得非常臃肿。
- 最致命的缺陷,增加产品时,就要修改工厂类。违反开闭原则。
由此又衍生出了工厂方法模式
public class postive {
/*===============服务端======================*/
//-----------------------产品--------------------
interface Food{
void eat();
}
static class Hamburger implements Food {
@Override
public void eat() {
System.out.println("吃汉堡。。。。。");
}
}
static class Drumstick implements Food {
@Override
public void eat() {
System.out.println("吃鸡腿。。。。。");
}
}
static class Milk implements Food {
@Override
public void eat() {
System.out.println("喝牛奶。。。。。");
}
}
//--------------------------工厂-----------------------
interface FoodFactory {
Food getFood();
}
static class HamburgerFactory implements FoodFactory{
@Override
public Food getFood() {
return new Hamburger();
}
}
static class DrumstickFactory implements FoodFactory{
@Override
public Food getFood() {
return new Drumstick();
}
}
static class MilkFactory implements FoodFactory{
@Override
public Food getFood() {
return new Milk();
}
}
/*=================客户端===================*/
public static void main(String[] args) {
FoodFactory foodFactory = new MilkFactory();
Food food01 = foodFactory.getFood();
food01.eat();
}
}
uml如下:
此时,完美解决了简单工厂的几个缺点。
这里就会有聪明的小问号有很多朋友了:
- 如果源代码作者修改相关工厂类的类名,那这时候调用工厂类的客户端代码就需要修改了,这不如简单工厂呢?
其实,在程序界有个约定俗成的“潜规则”,接口类一般不允许进行修改(非必须),而工厂类在实际使用中,是相当于接口类的,工厂类作者有责任,有义务保证工厂类的类名是稳定的,也就是说,工厂类是比产品类更加稳定的。
既然使我们后面自己扩展的Rice类,为什么不直接实例化它,直接使用。我们就是作者,为什么不能直接使用?
这里需要扩展一下,有时候一个产品类并不是孤立的,它和其他类一起组成一个服务框架。用Java中的泛型变可将自己新添加的类融入框架中啦!
下面增加一些类:
/*===============服务端======================*/
//------------------------产品质检流程-----------------------、
static class QualityInspection {
public void checking(FoodFactory foodFactory){
System.out.println("====start====");
Food food = foodFactory.getFood();
food.eat();
System.out.println("====end====");
}
}
/*=================客户端===================*/
public static void main(String[] args) {
FoodFactory foodFactory01 = new MilkFactory();
QualityInspection inspection = new QualityInspection();
inspection.checking(foodFactory01);
但是,每个产品都扩展一个工厂类出来,很容易造成类爆炸,那如何来解决这个问题呢?此时就轮到我们的抽象工厂模式登场了
针对工厂方法模式的缺陷,抽象工厂模式进行了改进,一个工厂负责创建一个产品簇的对象。
关于产品簇:是指多个存在内在联系的或者存在逻辑关系的产品。
简单的说,抽象工厂模式就是将一个产品簇封装到一个工厂中,以此来减少工厂模式中工厂的数量,uml如图所示
下面我们用机械型号来写代码理解:
public class postive {
/*===============服务端======================*/
//-----------------------产品--------------------
/*----------------螺丝---------------------*/
interface Screw{
void createScrew();
}
static class Screw_06 implements Screw {
@Override
public void createScrew() {
System.out.println("create Screw_06 666666。。。。。");
}
}
static class Screw_08 implements Screw {
@Override
public void createScrew() {
System.out.println("create Screw_08 8888888。。。。。");
}
}
/*----------------螺母---------------------*/
interface Nut{
void createNut();
}
static class Nut_06 implements Nut {
@Override
public void createNut() {
System.out.println("create Nut_06 666666。。。。。");
}
}
static class Nut_08 implements Nut {
@Override
public void createNut() {
System.out.println("create Nut_08 8888888。。。。。");
}
}
//--------------------------工厂-----------------------
interface ComponentsFactory {
Screw getScrew();
Nut getNut();
}
/*----------------6号工厂---------------------*/
static class Factory_666 implements ComponentsFactory {
@Override
public Screw getScrew() {
return new Screw_06();
}
@Override
public Nut getNut() {
return new Nut_06();
}
}
/*----------------8号工厂---------------------*/
static class Factory_888 implements ComponentsFactory {
@Override
public Screw getScrew() {
return new Screw_08();
}
@Override
public Nut getNut() {
return new Nut_08();
}
}
//------------------------产品质检流程-----------------------、
static class QualityInspection {
public void checking(ComponentsFactory Factory){
System.out.println("我是人肉质检员。。。。。等待产出零件 -_- ");
Screw screw = Factory.getScrew();
Nut nut = Factory.getNut();
screw.createScrew();
nut.createNut();
System.out.println("开始质检.......");
System.out.println(" ");
}
}
/*=================客户端===================*/
public static void main(String[] args) {
ComponentsFactory Factory01 = new Factory_666();
ComponentsFactory Factory02 = new Factory_888();
QualityInspection inspection = new QualityInspection();
inspection.checking(Factory01);
inspection.checking(Factory02);
}
}
抽象工厂模式延续了前两个模式的优点,区别就在于他将一个产品簇放在一个工厂中,实际运用时,需要划分好产品簇和产品等级。
缺点:产品簇新增一个产品时,需要每个工厂增加新产品。
所以
- 当产品簇比较固定时,考虑使用抽象工厂。
- 当产品经常变动时,不建议使用抽象工厂。