工厂模式(简单工厂、工厂方法和抽象工厂)

阅读: 评论:0

工厂模式(简单工厂、工厂方法和抽象工厂)

工厂模式(简单工厂、工厂方法和抽象工厂)

工厂模式

学习工厂模式必须知道的概念:

  1. 产品
  2. 抽象产品
    抽象类和接口
  3. 产品簇
    多个内在联系或者有逻辑关系的产品
    比如三秦套餐中:凉皮+冰峰+肉夹馍
  4. 产品等级

产品等级和产品簇的关系:

我们平时创建对象的方式:

//抽象产品
interface Foot {void eat();
}
//具体产品(汉堡包
class Hamburger implements com.shi.design.simple_factory.Foot {@Overridepublic void eat() {System.out.println("在吃汉堡包!");}
}
//上面代码为服务端,下面为客户端,我们身份为客户身份,不能修改服务端代码
//=============================================
public class Test {public static void main(String[] args) {Foot f = new Hamburger();f.eat();}
}

上面的这种设计十分脆弱,因为只要服务端修改了代码,客户端也必须跟着修改,这样的设计,服务端和客户端是耦合的。我们需要的是,无论服务端怎么修改,我们客户端的代码是不需要改变的。

简单工厂模式

针对上面的问题,我们采用简单工厂模式进行修改

//抽象产品
interface Foot {void eat();
}//具体产品(汉堡包
class Hamburger implements Foot {@Overridepublic void eat() {System.out.println("在吃汉堡包!");}
}//具体产品(米线
class RiceNoodle implements Foot {@Overridepublic void eat() {System.out.println("在吃米线!");}
}//简单工厂类
class FootFactory {public static Foot getFoot(int type) {Foot foot = null;switch (type) {case 1:foot = new Hamburger();break;case 2:foot = new RiceNoodle();break;}return foot;}
}//时光线----上面为很久以前的代码,我们不能修改,下面为现在我们书写的代码
//==================================================
//
public class AppTest {public static void main(String[] args) {Foot foot = Foot(1);foot.eat();}
}

简单工厂的优点:

  1. 将具体产品的类型从客户端中解耦出来
  2. 服务器端如果修改了具体产品的类名,客户端也不知道
  3. 这复合了面向接口编程的思想

缺点:

  1. 客户端不得不死记硬背那些常量与具体产品的映射关系
  2. 如果具体产品特别多,那么简单工厂就会别的特别臃肿,比如如果有一百个具体产品,那么就得有100个case
  3. 如果变化来了,客户端需要新添加方法,那么就得修改简单工厂中的内容,不符合开闭原则

简单工厂的UML类图

工厂方法模式

针对于简单工厂产生的问题,我们使用工厂方法模式

interface Foot {void eat();
}//具体产品(汉堡包
class Hamburger2 implements Foot {@Overridepublic void eat() {System.out.println("在吃汉堡包!");}
}//具体产品(米线
class RiceNoodle implements Foot {@Overridepublic void eat() {System.out.println("在吃米线!");}
}//设置工厂接口
interface FootFactory {Foot getFoot();
}//汉堡包工厂
class HambergerFactory implements FootFactory {@Overridepublic Foot getFoot() {return new Hamburger2();}
}//米线接口
class RiceNoodleFactory implements FootFactory {@Overridepublic Foot getFoot() {return new RiceNoodle();}
}class Product {public static void Evaluate(FootFactory footFactory){Foot foot = Foot();System.out.println("评委A开始品尝");foot.eat();Foot foot1 = Foot();System.out.println("评委B开始品尝");foot1.eat();Foot foot2 = Foot();System.out.println("评委C开始品尝");foot2.eat();}
}//===================================
//扩充方法
class ColdRice implements Foot {@Overridepublic void eat() {System.out.println("在吃凉皮!");}
}//凉皮创建工厂
class ColdRiceFactory implements FootFactory {@Overridepublic Foot getFoot() {return new ColdRice();}
}public class AppTest {public static void main(String[] args) {HambergerFactory hambergerFactory = new HambergerFactory();Foot foot = Foot();foot.eat();Product.Evaluate(new HambergerFactory());}
}

优点:

  1. 仍然具有简单工厂的优点,服务器端修改了具体的产品的类名以后,客户端不知道
  2. 当客户端需要新添加一个新的产品时,不需要修改作者原来的代码,只需要扩展一个新的工厂

杆点:

  1. 我们都知道,简单工厂也好,工厂方法也好,都有一个优点,就是服务器端的具体类名修改了以后,客户端不知道!但是,反观我们现在的代码,客户端依然依赖于服务器端具体工厂的类名呀,要是服务器端的具体工厂的类名修改了,那么不是本地的调用的方法内部也得修改?
    解释: 工厂的名称,视为接口,作者有责任有义务保证工厂的名称是稳定的,也就是说,虽然客户端依赖于工厂的具体类名,可是在IT行业内,所有工厂的名字都是趋向于稳定的(并不是100%不会变),但是至少工厂类的名称,要比具体类的名字更加稳定。
  2. 既然产品是我们客户端自己扩展出来的,那么为什么不直接自己实例化呢,毕竟自己扩展出来的ColdRice这个产品,自己能够把控,为什么还要创建工厂呢?
    解释: 作者开发功能的时候,不仅仅会开发一些抽象产品,具体产品,对应的工厂,还会套配一些提前做好的架构,比如上面服务端提供的Product的品尝功能。
  3. 现在只做出ColdRiceFactory,是为了把ColdRiceFactory传入到Product.Evaluate中,所以需要需要创建这个ColdRiceFactory,那么为什么从一开始,就让Product.Evaluate接收的是Food参数呢,而不现在的FoodFactory参数?
    解释: 1)、那么在客户端传入的时候就需要传入具体类名,而不是传入工厂,那么如果传入具体类名,那么服务端具体名称修改,则我们也需要修改,2)、该业务品尝中,如果传入Foot的话,那么就是每一个评委都是吃的是同一份食物,而传入FootFactory则每一个评委在吃食物的时候就可以自己new一份食物而不是吃上一个吃剩下的。

缺点: 如果有多个产品等级,那么工厂类的数量就会爆炸式增长。

工厂方法模式的UML类图:

抽象工厂方法

针对工厂方法模式的缺点,我们使用抽象工厂模式。
简单来说,其实抽象工厂与工厂的区别就是将造对象的过程模拟化,比如,套餐,所有店里面都有吃和喝的,所以创建的时候就将吃和喝的放在同一个工厂里面创建,从而减少代码。

//食物接口
interface Foot {void eat();
}//具体产品(汉堡包
class Hamburger implements Foot {@Overridepublic void eat() {System.out.println("在吃汉堡包!");}
}//具体产品(米线
class RiceNoodle implements Foot {@Overridepublic void eat() {System.out.println("在吃米线!");}
}
//饮料接口
interface Drink {public void drink();
}//抽象产品  可乐
class Cola implements Drink {@Overridepublic void drink() {System.out.println("在喝可乐");}
}//抽象产品  冰峰
class IcePeak implements Drink {@Overridepublic void drink() {System.out.println("在喝冰峰");}
}//设置工厂接口
interface Factory {Foot getFoot();Drink getDrink();
}//肯德基(KFC)工厂
class KFCFactory implements Factory {@Overridepublic Foot getFoot() {return new Hamburger();}@Overridepublic Drink getDrink() {return new Cola();}
}//三秦工厂
class SanQinFactory implements Factory {@Overridepublic Foot getFoot() {return new RiceNoodle();}@Overridepublic Drink getDrink() {return new IcePeak();}
}class Product {public static void Evaluate(Factory footFactory){Foot foot = Foot();Drink drink = Drink();System.out.println("评委A开始品尝");foot.eat();drink.drink();Foot foot1 = Foot();Drink drink1 = Drink();System.out.println("评委B开始品尝");foot1.eat();drink1.drink();Foot foot2 = Foot();Drink drink2 = Drink();System.out.println("评委C开始品尝");foot2.eat();drink2.drink();}
}//===================================
public class AppTest {public static void main(String[] args) {KFCFactory kfcgerFactory = new KFCFactory();Foot foot = Foot();foot.eat();Product.Evaluate(new KFCFactory());}
}

优点:

  1. 任然具有普通工厂和抽象工厂的优点,
  2. 更重要的是,抽象工厂吧工厂类的数量减少了,无论多少个产品等级工厂就一套。

杆点:

  1. 为啥三秦工厂的时候就是米粉加冰峰,不可以是米粉加可乐?
    解释: 抽象工厂中,可以生产多个产品, 这多个产品之间,必须都存内在联系。

缺点:

  1. 当产品等级发生变化时(添加商品等级,删除商品等级的时候),都会引起所有工厂代码的修改,就违反了开闭原则。

抽象工厂UML类图

结论:当产品等级比较固定,就可以考虑使用抽象工厂,如果产品等级经常变化,则不建议使用抽象工厂。

以上内容为课后总结,如有侵权,请告知本人!

本文发布于:2024-01-28 10:40:42,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/17064096466839.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:工厂   抽象   模式   简单   方法
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23