【Java设计模式 02】工厂方法模式

就像一个工厂不断地生产零件一样,把创建对象的流程集中封装在一个工厂类中,这就是简单工厂模式,属于创建型设计模式

抽象产品类,即Shape,描述产品的通用行为。接着具体产品类可以继承自Shape,例如Circle或者Square。再由工厂类ShapeFactory 的创造方法createShape里的if-else逻辑返回具体产品类

这样做的好处就是,客户端没有必要访问具体的产品类,而是只通过访问工厂类,调用工厂方法来获取具体产品,从而降低了耦合。但是如果需要添加新的产品,就需要修改工厂类的代码。

为了解决该问题,我们可以在简单工厂模式的基础之上,对工厂这个概念再做一个抽象,引入抽象工厂和具体工厂的概念,从而添加新的产品只需要添加新的工厂类而无需修改原来的代码。这样就使得产品的生产更加灵活,支持扩展,符合开闭原则。符合这种核心设计思想的设计模式就是工厂方法模式。

Java代码:

// 抽象产品
interface Shape {
    void draw();
}

// 具体产品-圆形
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Circle");
    }
}

// 具体产品-正方形
class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("Square");
    }
}

// 抽象工厂
interface ShapeFactory {
    Shape createShape();
}

// 具体工厂-创建圆形
class CircleFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Circle();
    }
}


// 具体工厂-创建正方形
class SquareFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Square();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        ShapeFactory circleFactory = new CircleFactory();
        Shape circle = circleFactory.creaeteShape();
        circle.draw();    // 输出:Circle

        ShapeFactory squareFactory = new SquareFactory();
        Shape square = squareFactory.createShape();
        square.draw();    // 输出:Square
    }
}

在Java中,interface关键字用来定义接口。接口是一种抽象类型,它定义了一组方法的规范,但没有提供方法的具体实现。

接口定义了一个类应该具有的方法和常量,它描述了一个对象的行为而不关注其具体实现。接口可以包含方法的签名、常量和默认方法。一个类可以通过实现一个或多个接口来扩展其功能,实现接口的类必须提供接口中所有方法的具体实现。

接口的作用是:

  1. 定义一组方法的规范:接口定义了一组方法的签名,描述了一个类应该具有的行为,实现接口的类必须提供这些方法的具体实现。

  2. 实现多态性:通过接口,一个类可以具备多个不相关的类型。这使得代码更具灵活性,能够以不同的方式处理对象。

  3. 实现代码复用:接口可以被多个类实现,这样不同的类可以共享接口中定义的方法。

  4. 支持类之间的松耦合关系:通过接口,类之间可以通过接口进行交互,而不是直接依赖于具体的实现类。这样可以降低类之间的耦合度,提高代码的可维护性和可扩展性。

总而言之,接口提供了一种规范和契约,使得多个类可以按照相同的接口进行通信和交互。它是实现多态性、提高代码复用和降低类之间耦合度的重要工具。

在Java中,implements关键字用来表示一个类实现了一个接口,即实现了接口中定义的所有方法。通过implements关键字,一个类可以继承接口中的方法签名,并提供自己的实现。

具体来说,当一个类使用implements关键字来实现一个接口时,它必须提供接口中定义的所有方法的实现。这意味着该类必须具有与接口中定义的方法相同的方法名、参数列表和返回类型。否则,编译器将报错。

使用implements关键字的主要作用是实现接口的多态性。通过实现接口,一个类可以在不改变其继承关系的情况下,具备多个不相关的类型。这使得代码更具灵活性和可扩展性,可以实现更高层次的抽象。同时,通过将类声明为接口的实现类,可以确保该类符合接口定义的规范,提高代码质量和可维护性。

另外,一个类可以同时实现多个接口,只需使用逗号分隔多个接口名称即可。这使得类能够具备多个不同接口的特性和行为。

总结一下,什么时候使用工厂方法模式:当创建对象涉及一系列复杂的初始化逻辑,而且这些逻辑在不同的子类中可能有所不同时,可以用工厂方法模式将这些初始化逻辑封装在子类的工厂中。

工厂模式的应用:Spring框架中的Bean工厂:通过配置文件或注解,Spring可以根据配置信息动态地创建和管理对象;JDBC中的Connection工厂:在Java数据库连接中,DriverManager使用工厂方法模式来创建数据库连接。不同的数据库驱动(如MySQL、PostgreSQL等)都有对应的工厂来创建连接。

【设计模式专题之工厂方法模式】2.积木工厂

CPP代码题解:

#include <iostream>
#include <vector>
 
// 抽象积木接口
class Block {
public:
    virtual void produce() = 0;
};
 
// 具体圆形积木实现
class CircleBlock : public Block {
public:
    void produce() override {
        std::cout << "Circle Block" << std::endl;
    }
};
 
// 具体方形积木实现
class SquareBlock : public Block {
public:
    void produce() override {
        std::cout << "Square Block" << std::endl;
    }
};
 
// 抽象积木工厂接口
class BlockFactory {
public:
    virtual Block* createBlock() = 0;
};
 
// 具体圆形积木工厂实现
class CircleBlockFactory : public BlockFactory {
public:
    Block* createBlock() override {
        return new CircleBlock();
    }
};
 
// 具体方形积木工厂实现
class SquareBlockFactory : public BlockFactory {
public:
    Block* createBlock() override {
        return new SquareBlock();
    }
};
 
// 积木工厂系统
class BlockFactorySystem {
private:
    std::vector<Block*> blocks;
 
public:
    void produceBlocks(BlockFactory* factory, int quantity) {
        for (int i = 0; i < quantity; i++) {
            Block* block = factory->createBlock();
            blocks.push_back(block);
            block->produce();
        }
    }
 
    const std::vector<Block*>& getBlocks() const {
        return blocks;
    }
 
    ~BlockFactorySystem() {
        // 释放所有动态分配的积木对象
        for (Block* block : blocks) {
            delete block;
        }
    }
};
 
int main() {
    // 创建积木工厂系统
    BlockFactorySystem factorySystem;
 
    // 读取生产次数
    int productionCount;
    std::cin >> productionCount;
 
    // 读取每次生产的积木类型和数量
    for (int i = 0; i < productionCount; i++) {
        std::string blockType;
        int quantity;
        std::cin >> blockType >> quantity;
 
        if (blockType == "Circle") {
            factorySystem.produceBlocks(new CircleBlockFactory(), quantity);
        } else if (blockType == "Square") {
            factorySystem.produceBlocks(new SquareBlockFactory(), quantity);
        }
    }
 
    return 0;
}

在C++中,virtual关键字用于声明一个虚函数。虚函数是一个在基类中被声明为虚函数的成员函数,它可以在派生类中被重写。使用virtual关键字可以实现多态性,即通过基类的指针或引用调用派生类中的重写函数。

virtual关键字的作用主要有以下几点:

  1. 实现动态绑定:当使用基类的指针或引用来调用一个虚函数时,会在运行时动态地决定调用哪个函数。这使得程序可以根据实际运行时的对象类型来调用适当的函数,实现多态性。

  2. 支持运行时多态性:通过虚函数机制,可以在基类中声明一个通用的接口,派生类根据自己的需要重写该虚函数,使得在程序运行时能够根据实际对象类型调用适当的函数版本。

  3. 方便扩展和修改:在后续的代码扩展和修改中,只需在派生类中重新实现需要修改的虚函数,而不需要修改基类的代码。这样可以避免对已有代码的大规模修改。

需要注意的是,只有通过指针或引用调用虚函数时才会发生动态绑定,通过对象调用虚函数时会使用静态绑定。因此,需要将基类的析构函数声明为虚函数,以确保在删除指向派生类对象的基类指针时调用适当的析构函数,避免内存泄漏。

总结而言,virtual关键字用于声明虚函数,实现动态绑定和多态性,支持运行时根据实际对象类型调用适当的函数,方便代码扩展和修改。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值