设计模式之工厂模式

学习工厂设计模式,必须知道的相关概念:
学习工厂设计模式,必须知道的相关概念:

1.产品:

​ 类

2.抽象产品:

​ 抽象类、接口

3.产品簇

​ 多个有内在联系,或者是有逻辑关系的产品。

4.产品等级

​ 不同产品,如可乐,冰封,都是饮料,但是是不同产品

简单工厂

把代码分为服务端和客户端代码

//客户端
public class AppTest {
    public static void main(String[] args) {
        Food food = new Hamburger();
        food.eat();
    }
}
//==========================================
//服务端
interface Food{
    void eat();
}
class Hamburger implements Food{
    //如果修改为Class Hamburger3 那么客户端new Hamburger3();违反了接口隔离和迪米特法则

    @Override
    public void eat() {
        System.out.println("吃汉堡");
    }
}
/**
 * 这种设计相当脆弱!为什么呢? 因为,只要作者修改了具体产品的类名,那么客户端代码,也要随之一起改变。
 * 这样服务器端代码,和客户端代码就是耦合的!*/

我们尝试用简单工厂来解决

模式的结构

​ 工厂角色(Creator):这是简单工厂模式的核心,由它负责创建所有的类的内部逻辑。当然工厂类必须能够被外界调用,创建所需要的产品对象。

​ 抽象(Product)产品角色:简单工厂模式所创建的所有对象的父类,注意,这里的父类可以是接口也可以是抽象类,它负责描述所有实例所共有的公共接口。

​ 具体产品(Concrete Product)角色:简单工厂所创建的具体实例对象,这些具体的产品往往都拥有共同的父类。

//客户端
public class AppTest2 {
    public static void main(String[] args) {
        FoodFactory.getFood(2).eat();
        FoodFactory.getFood(1).eat();
    }
}

//==========================================
//服务端
//抽象
interface Food2{
    void eat();
}
//简单工厂
class FoodFactory{
    public static Food2 getFood(int i){
        Food2 food2 = null;
        switch (i){
            case 1:
                food2 =  new Hamburger2();
                break;
            case 2:
                food2 = new RiceNoodle();
                break;
        }
        return food2;
    }
}
//具体产品
//米线
class RiceNoodle implements Food2{

    @Override
    public void eat() {
        System.out.println("吃米线");
    }
}

//汉堡
class Hamburger2 implements Food2{

    @Override
    public void eat() {
        System.out.println("吃汉堡");
    }

优点

1.把具体产品的类型,从客户端代码中,解耦出来。
2.服务器端,如果修改了具体产品的类名,客户端也知道!
这便符合了“面向接口编程的思想

缺点

1.客户端不得不死记硬背那些常量与具体产品的映射关系,比如: 1对应汉堡包,2 对应米线
2.如何具体产品特别多, 则简单工厂,就会变得十分臃肿。比如有100个具体产品,则需要在简单工厂的switch中写出100个case! .
3.最重要的是,变化来了:客户端需要扩展具体产品的时候,势必要修改简单工厂中的代码,这样便违反了“开闭原则”。

工厂方法

模式的结构

工厂方法模式的主要角色如下。

  1. 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。
  2. 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  3. 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
  4. 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应
//客户端
class AppTest {
    public static void main(String[] args) {
        Factory hamburgerFactory = new HamburgerFactory();
        hamburgerFactory.getFood().eat();
        Factory riceNoodleFactory = new RiceNoodleFactory();
        riceNoodleFactory.getFood().eat();

        Business.taste(new HamburgerFactory());
    }
}

//==========================================
//服务端
class Business{
    public static void taste(Factory factory){

        System.out.println("评委1,准备品尝");
        factory.getFood().eat();

        System.out.println("评委2,准备品尝");
        factory.getFood().eat();

        System.out.println("评委3,准备品尝");
        factory.getFood().eat();
    }
}
interface Factory{
    public Food getFood();
}
class HamburgerFactory implements Factory{
    @Override
    public Food getFood() {
        return new Hamburger();
    }
}
class RiceNoodleFactory implements Factory{
    @Override
    public Food getFood() {
        return new RiceNoodle();
    }
}
interface Food{
    void eat();
}

//米线
class RiceNoodle implements Food{

    @Override
    public void eat() {
        System.out.println("吃米线");
    }
}

//汉堡
class Hamburger implements Food{

    @Override
    public void eat() {
        System.out.println("吃汉堡");
    }
}

优点

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

  • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
  • 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
  • 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。

杠点

1.我们已经知道, 简单工厂也好,厂方法也好,都有一个优点,就是服务器端的具体产品类名变化了以后,客户端不知道!
但是,反观我们现在的代码,客户端仍然依赖于具体的工厂的类名呀!此时,如果服务器端修改了具体工厂的类名,那么客户端也要随之一起修改! 感觉折腾了一圈,又回到了原点! ! !
解释:
工厂的名字,是为视为接口的。作者有责任,有义务,保证工厂的名字是稳定的。也就是说,虽然客户端依赖于工厂的具体类名,可是在IT业内,所有工厂的名字都是趋向于稳定(并不是100%不会变)。至少工厂类的名字,要比具体产品类的名字更加稳定!

2.既然产品是我们自己客户端扩展出来的,那为什么不直接自己实例化呢?毕竟这个扩展出来的Lp这个产品,我们自己就是作者。我们想怎么改类名自己都能把控!为什么还要为自己制作的产品做工厂呢?
解释:
因为,作者在开发功能时,不仅仅只会开发一些抽象产品、具体产品、对应的工厂,还会配套地搭配-些提前做好的框架。

**3.**现在制作出LpFactory, 是为了能把LpFactory传入给Bussiness. taste方法,所以,必须定义这个LpFactory.那为什么不从一开始,
就让Bussiness . taste方法就直接接受Food参数呢?而不是现在的FoodFactory作为参数。

解释:

​ 传参数Food,是因为Food类名不如工厂稳定,另外一个就是,传参都是一个Food,并不会产生新对象。

缺点

  • 类的个数容易过多,增加复杂度
  • 增加了系统的抽象性和理解难度
  • 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。

抽象工厂

模式的结构

抽象工厂模式的主要角色如下。

  1. 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
  2. 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
  3. 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
  4. 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

在这里插入图片描述
在这里插入图片描述

//客户端
class AppTest {
    public static void main(String[] args) {
        Business.taste(new KFCFactory());
    }
}

//==========================================
//服务端

class Business{
    public static void taste(Factory factory){

        System.out.println("评委1,准备品尝");
        factory.getFood().eat();
        factory.getDrink().drink();

        System.out.println("评委2,准备品尝");
        factory.getFood().eat();
        factory.getDrink().drink();

        System.out.println("评委3,准备品尝");
        factory.getFood().eat();
        factory.getDrink().drink();
    }
}

interface Factory{
    public Food getFood();
    public Drink getDrink();
}

class KFCFactory implements Factory{
    @Override
    public Food getFood() {
        return new Hamburger();
    }

    @Override
    public Drink getDrink() {
        return new Cola();
    }
}

class SanQinFactory implements Factory{
    @Override
    public Food getFood() {
        return new RiceNoodle();
    }

    @Override
    public Drink getDrink() {
        return new Ice();
    }
}

interface Food{
    void eat();
}
interface Drink{
    void drink();
}
//米线
class RiceNoodle implements Food{

    @Override
    public void eat() {
        System.out.println("吃米线");
    }
}

//汉堡
class Hamburger implements Food{

    @Override
    public void eat() {
        System.out.println("吃汉堡");
    }
}
class Cola implements Drink{
    @Override
    public void drink() {
        System.out.println("喝可乐");
    }
}
class Ice implements Drink{

    @Override
    public void drink() {
        System.out.println("喝冰峰");
    }
}

抽象工厂的

优点

1.仍然有简单工厂和工厂方法的优点

2.更重要的是,抽象工厂把工厂类的数量减少了! 无论有多少个产品等级,工厂就一套

使用抽象工厂模式一般要满足以下条件。

  • 系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品。
  • 系统一次只可能消费其中某一族产品,即同族的产品一起使用。

杠点

1.为什么三秦工厂中,就必须是米线搭配冰峰呢?为什么就不能是米线搭配可乐?
解释:
抽象工厂中,可以生产多个产品,这多个产品之间,必须有内在联系。
同一个工厂中的产品都属于同-一个产品簇! !不能把不同产品簇中的产品混合到-一个抽象工厂的实现类中。

缺点

1.当产品等级发生变化时(增加产品等级、删除产品等级),都要引起所有以前工厂代码的修改,这就违反了“开闭原则”!

结论

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

产品不扩充,简单工厂最好,产品等级只有一个,工厂方法最好。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值