ITPub博客

首页 > 数据库 > 数据库开发技术 > 创建型设计模式(二):工厂模式 & 抽象工厂模式 & 建造者模式

创建型设计模式(二):工厂模式 & 抽象工厂模式 & 建造者模式

原创 数据库开发技术 作者:灸哥漫谈 时间:2023-12-14 00:05:51 0 删除 编辑

工厂模式

一、什么是工厂模式

工厂模式旨在提供一种统一的接口来创建对象,而将具体的对象实例化的过程延迟到子类或者具体实现中。有助于降低客户端代码与被创建对象之间的耦合度,提高代码的灵活性和可维护性。

定义了一个创建对象的接口,但不负责具体对象的实例化。而是将实例化的责任交给它的子类或者具体实现,这种模式包括抽象工厂、工厂方法和简单工厂等不同形式。

二、为什么使用工厂模式

  1. 降低耦合度:工厂模式将客户端代码与具体的类实现分离,降低它们之间的耦合度,客户端只需要知道工厂接口或者抽象类,而无需关心具体的实现细节。

  2. 可扩展性:当需要添加新的产品类时,只需要创建一个新的具体工厂类和产品类,而不需要修改已有的代码,有助于系统的可扩展性,符合开闭原则。

  3. 隐藏实现细节:工厂模式将对象的创建过程封装在工厂类中,客户端无需知道对象的具体创建细节,有助于隐藏实现细节,提高系统的安全性。

三、如何实现工厂模式

简单工厂模式

简单工厂模式是工厂模式的一种简化形式,包含了一个具体工厂类,负责创建产品的对象。

// 抽象产品类interface Product {    void display();}
// 具体产品类Aclass ConcreteProductA implements Product { @Override public void display() { System.out.println("Product A"); }}
// 具体产品类Bclass ConcreteProductB implements Product { @Override public void display() { System.out.println("Product B"); }}
// 简单工厂类class SimpleFactory { public static Product createProduct(String type) { switch (type) { case "A": return new ConcreteProductA(); case "B": return new ConcreteProductB(); default: throw new IllegalArgumentException("Invalid product type"); } }}
// 客户端代码public class Client { public static void main(String[] args) { Product productA = SimpleFactory.createProduct("A"); productA.display(); // Output: Product A
Product productB = SimpleFactory.createProduct("B"); productB.display(); // Output: Product B }}

工厂方法模式

工厂方法模式定义了一个创建产品的接口,具体的产品创建由其子类负责实现。

// 抽象产品类interface Product {    void display();}
// 具体产品类Aclass ConcreteProductA implements Product { @Override public void display() { System.out.println("Product A"); }}
// 具体产品类Bclass ConcreteProductB implements Product { @Override public void display() { System.out.println("Product B"); }}
// 抽象工厂接口interface Factory { Product createProduct();}
// 具体工厂类Aclass ConcreteFactoryA implements Factory { @Override public Product createProduct() { return new ConcreteProductA(); }}
// 具体工厂类Bclass ConcreteFactoryB implements Factory { @Override public Product createProduct() { return new ConcreteProductB(); }}
// 客户端代码public class Client { public static void main(String[] args) { Factory factoryA = new ConcreteFactoryA(); Product productA = factoryA.createProduct(); productA.display(); // Output: Product A
Factory factoryB = new ConcreteFactoryB(); Product productB = factoryB.createProduct(); productB.display(); // Output: Product B }}

四、是否存在缺陷和不足

  1. 类爆炸:随着产品类的增加,工厂类的数量也会呈现指数级增长,导致类的爆炸,不利于系统的维护。

  2. 违背开闭原则:每次添加新产品都需要修改工厂类,违背了开闭原则,当有新产品加入时,必须修改所有工厂类。


五、如何缓解缺陷和不足

  1. 使用抽象工厂模式:抽象工厂模式将一组相关的产品封装在一起,形成一个产品族,每个具体工厂负责创建一族产品,缓解了类的爆炸问题,

  2. 依赖注入:将工厂的创建过程交给外部来管理,通过依赖注入的方式,避免了工厂类的频繁修改。

  3. 使用反射:可以使用反射机制,动态地创建产品对象,从而减少了工厂类的数量。


通过以上缓解措施,可以在一定程度上提高工厂模式的灵活性和可维护性,使其更好地适应变化。在实际应用中,根据具体场景选择合适的工厂的模式,并结合其他设计模式,以达到代码的清晰和可扩展,


抽象工厂模式

一、什么是抽象工厂模式

抽象工厂模式提供了一个接口,用于创建与产品家族相关的对象,无需制定具体类,有助于确保创建的对象能够相互配合使用,而无需指定具体的类。

抽象工厂模式提供了一种将一组相关的产品组合成一个家族的方式,而不必指定具体的类,通过引入抽象工厂接口和一组具体工厂类,为每个产品提供一个独立的工厂,从而使系统更具灵活性。

二、为什么使用抽象工厂模式

  1. 产品家族一致性:抽象工厂模式确保创建的对象相互之间是兼容的,属于同一产品家族,有助于保持系统的一致性。

  2. 易于替换:由于客户端只依赖于抽象接口,而不直接依赖具体类,因此可以轻松替换整个产品家族的实现,而无需修改客户端代码。

  3. 隐藏实现细节:客户端无需知道具体产品的实现细节,只需要了解抽象工厂接口,从降低了系统的复杂度。

三、如何实现抽象工厂模式

示例:图形界面库的抽象工厂模式,包含图形界面库中的按钮和文本框。

// 抽象按钮接口interface Button {    void display();}
// 具体按钮Aclass ButtonA implements Button { @Override public void display() { System.out.println("Button A"); }}
// 具体按钮Bclass ButtonB implements Button { @Override public void display() { System.out.println("Button B"); }}
// 抽象文本框接口interface TextBox { void display();}
// 具体文本框Aclass TextBoxA implements TextBox { @Override public void display() { System.out.println("TextBox A"); }}
// 具体文本框Bclass TextBoxB implements TextBox { @Override public void display() { System.out.println("TextBox B"); }}
// 抽象工厂接口interface GUIFactory { Button createButton(); TextBox createTextBox();}
// 具体工厂Aclass GUIFactoryA implements GUIFactory { @Override public Button createButton() { return new ButtonA(); }
@Override public TextBox createTextBox() { return new TextBoxA(); }}
// 具体工厂Bclass GUIFactoryB implements GUIFactory { @Override public Button createButton() { return new ButtonB(); }
@Override public TextBox createTextBox() { return new TextBoxB(); }}
// 客户端代码public class Client { public static void main(String[] args) { // 使用工厂A创建按钮和文本框 GUIFactory factoryA = new GUIFactoryA(); Button buttonA = factoryA.createButton(); TextBox textBoxA = factoryA.createTextBox();
buttonA.display(); // Output: Button A textBoxA.display(); // Output: TextBox A
// 使用工厂B创建按钮和文本框 GUIFactory factoryB = new GUIFactoryB(); Button buttonB = factoryB.createButton(); TextBox textBoxB = factoryB.createTextBox();
buttonB.display(); // Output: Button B textBoxB.display(); // Output: TextBox B }}

四、是否存在缺陷和不足

  1. 不易扩展新的产品家族:当需要添加新的产品家族时,需要修改抽象工厂接口及其所有的实现类,违背了开闭原则,使得系统扩展性受限。

  2. 复杂性增加:随着产品家族的增加,抽象工厂模式的类和接口数量可能呈现指数级增长,导致系统复杂性增加。

五、如何缓解缺陷和不足

  1. 使用依赖注入:将工厂的创建过程交给外部来管理,通过依赖注入的方式,避免了工厂类的频繁修改。

  2. 使用反射:可以使用反射机制,动态地创建产品对象,从而减少了工厂类和产品类的数量。

  3. 使用配置文件:将产品家族的配置信息放置在配置文件中,通过读取配置文件的方式动态创建工厂和产品对象,提高了系统的灵活性。



建造者模式

一、什么是建造者模式

建造者模式旨在通过将复杂对象的构造过程分离成多个简单的步骤,使得同样的创建过程可以创建不同的表示,有助于客户端代码能够根据需求选择构建过程的不同组合,以创建不同属性的对象。

将一个复杂对象的构建与其表示分离,使得同样的创建过程可以创建不同的表示,主要包含以下角色:

  • 产品

  • 抽象建造者

  • 具体建造者

  • 指挥者


二、为什么使用建造者模式

  1. 分布创建:建造者模式允许按照步骤构建一个复杂对象,使得客户端代码可以选择性地构建对象的不同部分,灵活性更高。

  2. 隔离复杂性:将构建过程在具体的建造者中,客户端无需关心构建的细节,从而降低了系统的复杂性。

  3. 可扩展性:可以通过增加新的具体的建造者类来扩展系统,而不影响已有的客户端代码。


三、如何实现建造者模式

设计实现一个电脑组装的建造者模式

// 产品类class Computer {    private String cpu;    private String memory;    private String storage;
public Computer(String cpu, String memory, String storage) { this.cpu = cpu; this.memory = memory; this.storage = storage; }
// Getters... public void display() { System.out.println("Computer Specs: CPU-" + cpu + ", Memory-" + memory + ", Storage-" + storage); }}
// 抽象建造者interface ComputerBuilder { void buildCPU(String cpu); void buildMemory(String memory); void buildStorage(String storage); Computer getResult();}
// 具体建造者Aclass ConcreteBuilderA implements ComputerBuilder { private Computer computer;
public ConcreteBuilderA() { this.computer = new Computer("", "", ""); }
@Override public void buildCPU(String cpu) { computer = new Computer(cpu, computer.getMemory(), computer.getStorage()); }
@Override public void buildMemory(String memory) { computer = new Computer(computer.getCpu(), memory, computer.getStorage()); }
@Override public void buildStorage(String storage) { computer = new Computer(computer.getCpu(), computer.getMemory(), storage); }
@Override public Computer getResult() { return computer; }}
// 具体建造者Bclass ConcreteBuilderB implements ComputerBuilder { private Computer computer;
public ConcreteBuilderB() { this.computer = new Computer("", "", ""); }
@Override public void buildCPU(String cpu) { computer = new Computer(cpu, computer.getMemory(), computer.getStorage()); }
@Override public void buildMemory(String memory) { computer = new Computer(computer.getCpu(), memory, computer.getStorage()); }
@Override public void buildStorage(String storage) { computer = new Computer(computer.getCpu(), computer.getMemory(), storage); }
@Override public Computer getResult() { return computer; }}
// 指挥者class Director { public void construct(ComputerBuilder builder) { builder.buildCPU("Intel i5"); builder.buildMemory("8GB"); builder.buildStorage("256GB SSD"); }}
// 客户端代码public class Client { public static void main(String[] args) { // 使用建造者A构建电脑 ComputerBuilder builderA = new ConcreteBuilderA(); Director director = new Director(); director.construct(builderA); Computer computerA = builderA.getResult(); computerA.display();
// 使用建造者B构建电脑 ComputerBuilder builderB = new ConcreteBuilderB(); director.construct(builderB); Computer computerB = builderB.getResult(); computerB.display(); }}

四、是否存在缺陷和不足

  1. 指挥者的变动:如果产品的构建步骤发生变化,指挥者类的代码也需要修改,违背了开闭原则。

  2. 不够灵活:当产品的构建步骤很多且相互关联时,建造者模式可能变得复杂且不够灵活。


五、如何缓解缺陷和不足

  1. 使用链式调用:在具体建造者中使用链式调用,使得客户端代码更加简洁,且不容易受到构建步骤变动的影响。

  2. 增加产品的变种:当产品的构建步骤较为复杂时,可以考虑增加产品的变种,以适应不同的构建需求。

  3. 使用反射和配置文件:可以通过反射机制和配置文件来动态配置产品的构建过程,提高系统的灵活性。


原文作者:灸哥漫谈;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2023-11-26

  • 博文量
    368
  • 访问量
    173291