A aplicação de vários modelos de fábrica

A aplicação de vários modelos de fábrica

Em java, tudo é um objeto, e esses objetos precisam ser criados. Se você criar um novo objeto diretamente ao criá-lo, o objeto será severamente acoplado. Se quisermos substituir o objeto, todos os lugares do novo objeto precisam a ser modificado, o que obviamente viola o princípio aberto-fechado do design de software. Se usarmos a fábrica para produzir objetos, só podemos lidar com a fábrica e desacoplar completamente do objeto.Se quisermos substituir o objeto, podemos substituir diretamente o objeto na fábrica, alcançando o objetivo de desacoplar do objeto; então, a maior vantagem do modelo de fábrica é: desacoplamento .

1. Padrão de fábrica simples (não 23 padrões de design)

Simple Factory não é um padrão de projeto, mas sim um hábito de programação.

1.1 Estrutura

  • Produto abstrato: define a especificação do produto e descreve as principais características e funções do produto .
  • Produtos concretos: implementam ou herdam subclasses de produtos abstratos
  • Fábrica de concreto: fornece um método para criar um produto e o chamador obtém o produto por meio desse método.

2.2 Implementação

2.2.1 Diagrama de classe de fábrica simples

O método de fábrica simples lida com os detalhes da criação do objeto. Uma vez disponível SimpleCoffeeFactory, o objeto CoffeeStore类no meio orderCoffee()torna-se o cliente deste objeto. Se você precisar do objeto Coffee posteriormente, poderá obtê-lo diretamente da fábrica. Desta forma, é liberado o acoplamento com a classe de implementação Coffee , e ao mesmo tempo , um novo acoplamento entre o objeto CoffeeStore e o objeto fábrica SimpleCoffeeFactory , e o acoplamento entre o objeto fábrica e o objeto mercadoria são gerados . Além de novas variedades de café , é inevitável a necessidade de modificação SimpleCoffeeFactorydo código, que viola o princípio do abrir e fechar . Pode haver muitos clientes da classe fábrica, neste momento apenas o código da classe fábrica precisa ser modificado, e outras operações de modificação são omitidas.

insira a descrição da imagem aqui

2.2.2 Código

/**
 * 抽象产品:咖啡
 */
public abstract class Coffee {
    
    
    // 抽象方法获取子类的咖啡的名称
    public abstract String getName();
    // 加糖
    public void addSugar() {
    
    
        System.out.println("加糖");
    }
    // 加奶
    public void addMilk() {
    
    
        System.out.println("加奶");
    }
}

/**
 * 具体产品:美式咖啡
 */
public class AmericanCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "美式咖啡";
    }
}

/**
 * 具体产品:拿铁咖啡
 */
public class LatteCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "拿铁咖啡";
    }
}

/**
 * 具体工厂:简单咖啡工厂类,用来生产咖啡
 */
public class SimpleCoffeeFactory {
    
    
    public Coffee createCoffee(String coffeeType){
    
    
        // 声明Coffee类型的变量,根据不同类型创建不同的coffee子类对象
        Coffee coffee;
        if("american".equals(coffeeType)){
    
    
            coffee = new AmericanCoffee();
        }else if ("latte".equals(coffeeType)){
    
    
            coffee = new LatteCoffee();
        }else {
    
    
            throw new RuntimeException("sorry,本店没有出售此类咖啡");
        }
        return coffee;
    }
}

/**
 * Coffee店
 */
public class CoffeeStore {
    
    
    public Coffee orderCoffee(String coffeeType){
    
    
        // 创建简单工厂来提供生产咖啡的方法
        SimpleCoffeeFactory factory = new SimpleCoffeeFactory();
        // 调用生产咖啡的方法
        Coffee coffee = factory.createCoffee(coffeeType);
        // 加配料
        coffee.addSugar();
        coffee.addMilk();
        return coffee;
    }
}

/**
 * 客户点咖啡
 */
public class Client {
    
    
    public static void main(String[] args) {
    
    
        //创建咖啡店类对象
        CoffeeStore store = new CoffeeStore();
        Coffee coffee = store.orderCoffee("latte");
        System.out.println(coffee.getName());
    }
}

2.2.3 Vantagens e desvantagens

vantagem:

O processo de criação de um objeto é encapsulado e o objeto pode ser obtido diretamente por meio de parâmetros. Separe a criação do objeto da camada de lógica de negócios, para evitar modificar o código do cliente no futuro. Se você deseja implementar um novo produto, pode modificar diretamente a classe de fábrica sem modificar o código original, o que reduz a possibilidade de cliente modificação de código e é mais fácil de expandir.

deficiência:

Ao adicionar novos produtos, ainda é necessário modificar o código da classe fábrica, o que viola o "princípio de abrir e fechar".

2. Padrão de fábrica estático (não 23 padrões de design)

Defina a função de criação de objetos na classe de fábrica como estático, este é o padrão de fábrica estático e não é um dos 23 padrões de design.

3.1 Código

/**
 * 抽象产品:咖啡
 */
public abstract class Coffee {
    
    
    // 抽象方法获取子类的咖啡的名称
    public abstract String getName();
    // 加糖
    public void addSugar() {
    
    
        System.out.println("加糖");
    }
    // 加奶
    public void addMilk() {
    
    
        System.out.println("加奶");
    }
}

/**
 * 具体产品:美式咖啡
 */
public class AmericanCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "美式咖啡";
    }
}

/**
 * 具体产品:拿铁咖啡
 */
public class LatteCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "拿铁咖啡";
    }
}

/**
 * 具体工厂:简单咖啡工厂类,用来生产咖啡
 */
public class SimpleCoffeeFactory {
    
    
    // 静态方法
    public static Coffee createCoffee(String coffeeType){
    
    
        // 声明Coffee类型的变量,根据不同类型创建不同的coffee子类对象
        Coffee coffee;
        if("american".equals(coffeeType)){
    
    
            coffee = new AmericanCoffee();
        }else if ("latte".equals(coffeeType)){
    
    
            coffee = new LatteCoffee();
        }else {
    
    
            throw new RuntimeException("sorry,本店没有出售此类咖啡");
        }
        return coffee;
    }
}

/**
 * Coffee店
 */
public class CoffeeStore {
    
    
    public Coffee orderCoffee(String coffeeType){
    
    
        // 不需要创建简单工厂来提供生产咖啡的方法
        // 直接类调用静态方法调用生产咖啡的方法
        Coffee coffee = SimpleCoffeeFactory.createCoffee(coffeeType);
        // 加配料
        coffee.addSugar();
        coffee.addMilk();
        return coffee;
    }
}

/**
 * 客户点咖啡
 */
public class Client {
    
    
    public static void main(String[] args) {
    
    
        //创建咖啡店类对象
        CoffeeStore store = new CoffeeStore();
        Coffee coffee = store.orderCoffee("latte");
        System.out.println(coffee.getName());
    }
}

3. Modo de fábrica

Defina uma interface para criar objetos e deixe as subclasses decidirem qual objeto de classe de produto instanciar. Os métodos de fábrica adiam a instanciação de uma classe de produto para suas subclasses de fábrica .

3.1 Estrutura

  • Abstract Factory (Abstract Factory): Fornece uma interface para criação de produtos, e o chamador a utiliza para acessar o método de fábrica da fábrica específica para criar produtos.
  • Concrete Factory (ConcreteFactory): Implementa principalmente o método abstrato na fábrica abstrata para completar a criação de produtos específicos.
  • Produto abstrato (Produto): define a especificação do produto e descreve as principais características e funções do produto.
  • Produto Concreto (ConcreteProduct): implementa a interface definida pelo papel abstrato do produto, e é criado por uma fábrica específica, e corresponde a uma fábrica específica one-to-one.

3.2 Implementação

3.2.1 Diagrama de classe padrão de fábrica

Ao adicionar categorias de produtos, as categorias de fábrica também devem ser adicionadas de acordo, e não há necessidade de modificar o código da categoria de fábrica, o que resolve as deficiências do modelo de fábrica simples.

O padrão de método de fábrica é uma abstração adicional do padrão de fábrica simples. Devido ao uso de polimorfismo , o padrão de método de fábrica mantém as vantagens do padrão de fábrica simples e supera suas deficiências.

insira a descrição da imagem aqui

3.2.2 Código

/**
 * 抽象产品:咖啡
 */
public abstract class Coffee {
    
    
    // 抽象方法获取子类的咖啡的名称
    public abstract String getName();
    // 加糖
    public void addSugar() {
    
    
        System.out.println("加糖");
    }
    // 加奶
    public void addMilk() {
    
    
        System.out.println("加奶");
    }
}

/**
 * 具体产品:美式咖啡
 */
public class AmericanCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "美式咖啡";
    }
}

/**
 * 具体产品:拿铁咖啡
 */
public class LatteCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "拿铁咖啡";
    }
}

/**
 * 抽象工厂
 */
public interface CoffeeFactory {
    
    
    //创建咖啡对象的方法
    Coffee createCoffee();
}

/**
 * 美式咖啡工厂对象,专门用来生产美式咖啡
 */
public class AmericanCoffeeFactory implements CoffeeFactory {
    
    
    @Override
    public Coffee createCoffee() {
    
    
        return new AmericanCoffee();
    }
}

/**
 * 拿铁咖啡工厂,专门用来生产拿铁咖啡
 */
public class LatteCoffeeFactory implements CoffeeFactory{
    
    
    @Override
    public Coffee createCoffee() {
    
    
        return new LatteCoffee();
    }
}

/**
 * Coffee店
 */
public class CoffeeStore {
    
    
    private CoffeeFactory factory;
    public void setFactory(CoffeeFactory factory) {
    
    
        this.factory = factory;
    }
    //点咖啡功能
    public Coffee orderCoffee() {
    
    
        Coffee coffee = factory.createCoffee();
        //加配料
        coffee.addMilk();
        coffee.addsugar();
        return coffee;
    }
}

/**
 * 客户点咖啡
 */
public class Client {
    
    
    public static void main(String[] args) {
    
    
        //创建咖啡店对象
        CoffeeStore store = new CoffeeStore();
        //创建对象
        //CoffeeFactory factory = new AmericanCoffeeFactory();
        CoffeeFactory factory = new LatteCoffeeFactory();
        store.setFactory(factory);
        //点咖啡
        Coffee coffee = store.orderCoffee();
        System.out.println(coffee.getName());
    }
}

3.2.3 Vantagens e desvantagens

vantagem:

  • Os usuários precisam apenas saber o nome da fábrica específica para obter o produto que desejam, sem conhecer o processo específico de criação do produto;
  • Ao adicionar novos produtos ao sistema, é necessário apenas adicionar categorias específicas de produtos e correspondentes categorias específicas de fábrica, sem qualquer modificação na fábrica original, e atender ao princípio de abertura e fechamento ;

deficiência:

  • Cada vez que um produto é adicionado, uma categoria específica de produto e uma categoria específica de fábrica correspondente devem ser adicionadas, o que aumenta a complexidade do sistema .

4. Padrão abstrato de fábrica

O padrão de fábrica abstrato é uma versão atualizada do padrão de método de fábrica. O padrão de método de fábrica produz apenas um nível de produtos, enquanto o padrão de fábrica abstrato pode produzir vários níveis de produtos . É uma estrutura padrão que fornece uma classe de acesso com uma interface para criar um grupo de objetos relacionados ou interdependentes, podendo a classe de acesso obter diferentes níveis de produtos da mesma família sem especificar a classe específica do produto desejado .

4.1 Estrutura

  • Abstract Factory (Fábrica Abstrata): Fornece uma interface para criação de produtos, que contém vários métodos para criar produtos, podendo criar vários produtos de diferentes níveis.
  • Fábrica Concreta : Implementa principalmente vários métodos abstratos na fábrica abstrata para concluir a criação de produtos específicos.
  • Produto abstrato (Produto): define a especificação do produto, descreve as principais características e funções do produto, e o padrão de fábrica abstrata possui vários produtos abstratos.
  • Produto Concreto : implementa a interface definida pelo papel abstrato do produto, e é criado por uma fábrica específica, possuindo uma relação muitos-para-um com a fábrica específica.

4.2 Implementação

4.2.1 Diagrama de classe padrão de fábrica abstrata

O negócio atual das cafeterias mudou, não só para produzir café, mas também para produzir sobremesas, como tiramisu, matcha mousse, etc. fábricas de mousse matcha e fábricas de sobremesas são propensas a explosões. Entre eles, café com leite e café americano são um tipo de produto, ambos são café; tiramisu e mousse de matcha também são um tipo de produto; café com leite e tiramisu são a mesma família de produtos (ou seja, ambos pertencem ao estilo italiano), Americano e mousse de matcha são da mesma família de produtos (ou seja, ambos pertencem ao sabor americano). Portanto, este caso pode ser implementado usando o padrão de fábrica abstrato.

insira a descrição da imagem aqui

4.2.2 Código

Se você deseja adicionar a mesma família de produtos, basta adicionar uma classe de fábrica correspondente e não precisa modificar outras classes.

/**
 * 抽象产品:咖啡
 */
public abstract class Coffee {
    
    
    // 抽象方法获取子类的咖啡的名称
    public abstract String getName();
    // 加糖
    public void addSugar() {
    
    
        System.out.println("加糖");
    }
    // 加奶
    public void addMilk() {
    
    
        System.out.println("加奶");
    }
}

/**
 * 具体产品:美式咖啡
 */
public class AmericanCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "美式咖啡";
    }
}

/**
 * 具体产品:拿铁咖啡
 */
public class LatteCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "拿铁咖啡";
    }
}

/**
 * 抽象产品:甜品
 */
public abstract class Dessert {
    
    
    public abstract void show();
}

/**
 * 具体产品:提拉米苏类
 */
public class Trimisu extends Dessert {
    
    
    public void show() {
    
    
        System.out.println("提拉米苏");
    }
}

/**
 * 具体产品:抹茶慕斯类
 */
public class MatchaMousse extends Dessert {
    
    
    public void show() {
    
    
        System.out.println("抹茶慕斯");
    }
}

/**
 * 抽象工厂: DessertFactory
 */
public interface DessertFactory {
    
    
    //生产咖啡的功能
    Coffee createCoffee();
    //生产甜品的功能
    Dessert createDessert();
}

/**
 * 美式风味的甜品工厂
 * 生产美式咖啡和抹茶慕斯
 */
public class AmericanDessertFactory implements DessertFactory {
    
    
    public Coffee createCoffee() {
    
    
        return new AmericanCoffee();
    }
    public Dessert createDessert() {
    
    
        return new MatchaMousse();
    }
}

/**
 * 意大利风味甜品工厂
 * 生产拿铁咖啡和提拉米苏甜品
 */
public class ItalyDessertFactory implements DessertFactory {
    
    
    public Coffee createCoffee() {
    
    
        return new LatteCoffee();
    }
    public Dessert createDessert() {
    
    
        return new Trimisu();
    }
}

/**
 * 客户类
 */
public class Client {
    
    
    public static void main(String[] args) {
    
    
        //创建的是意大利风味甜品工厂对象
        //ItalyDessertFactory factory = new ItalyDessertFactory();
        //创建的是美式风味甜品工厂对象
        AmericanDessertFactory factory = new AmericanDessertFactory();
        //获取拿铁咖啡和提拉米苏甜品
        Coffee coffee = factory.createCoffee();
        Dessert dessert = factory.createDessert();
        System.out.println(coffee.getName());
        dessert.show();
    }
}

4.2.3 Vantagens e desvantagens

vantagem:

Quando vários objetos em uma família de produtos são projetados para trabalhar juntos, isso garante que os clientes sempre usem apenas objetos da mesma família de produtos .

deficiência:

Quando um novo produto precisa ser adicionado à família de produtos, todas as classes de fábrica precisam ser modificadas.

4.2.4 Cenários de Uso

  • Quando os objetos a serem criados são uma série de famílias de produtos inter-relacionados ou interdependentes, como aparelhos de TV, máquinas de lavar e ar-condicionado em fábricas de eletrodomésticos.

  • Existem várias famílias de produtos no sistema, mas apenas uma delas é usada por vez. Por exemplo, alguém só gosta de usar roupas e sapatos de uma determinada marca.

  • A biblioteca de classes do produto é fornecida no sistema e todos os produtos têm a mesma interface, e o cliente não depende dos detalhes de criação e estrutura interna da instância do produto.

5. Extensão do modo

Desacople o objeto fábrica e o objeto produto através do modo fábrica + arquivo de configuração . Carregue o nome completo da classe no arquivo de configuração na classe de fábrica e crie um objeto para armazenamento.Se o cliente precisar do objeto, ele pode ser obtido diretamente.

5.1 Definir o arquivo de configuração

Defina um arquivo de configuração denominado bean.properties.

american=config_factory.AmericanCoffee
latte=config_factory.LatteCoffee

5.2 código

As variáveis ​​de membro estáticas são usadas para armazenar objetos criados (a chave armazena o nome e o valor armazena o objeto correspondente), enquanto a leitura de arquivos de configuração e a criação de objetos são escritas em blocos de código estático, de modo que precisam ser executados apenas uma vez.

/**
 * 抽象产品:咖啡
 */
public abstract class Coffee {
    
    
    // 抽象方法获取子类的咖啡的名称
    public abstract String getName();
    // 加糖
    public void addSugar() {
    
    
        System.out.println("加糖");
    }
    // 加奶
    public void addMilk() {
    
    
        System.out.println("加奶");
    }
}

/**
 * 具体产品:美式咖啡
 */
public class AmericanCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "美式咖啡";
    }
}

/**
 * 具体产品:拿铁咖啡
 */
public class LatteCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "拿铁咖啡";
    }
}

/**
 * 工厂类: CoffeeFactory
 * 加载配置文件,获取配置文件中配置的全类名,并创建该类的对象进行存储
 */
public class CoffeeFactory {
    
    
    // 定义容器对象存储咖啡对象
    private static HashMap<String,Coffee> map = new HashMap<String, Coffee>();
    // 加载配置文件, 只需要加载一次
    static {
    
    
        // 创建Properties对象
        Properties p = new Properties();
        // 调用p对象中的load方法进行配置文件的加载
        InputStream is = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties");
        try {
    
    
            p.load(is);
            // 从p集合中获取全类名并创建对象
            Set<Object> keys = p.keySet();
            for (Object key : keys) {
    
    
                String className = p.getProperty((String) key);
                // 通过反射技术创建对象
                Class clazz = Class.forName(className);
                Coffee coffee = (Coffee) clazz.newInstance();
                // 将名称和对象存储到容器中
                map.put((String)key,coffee);
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
    // 根据名称获取对象
    public static Coffee createCoffee(String name) {
    
    
        return map.get(name);
    }
}

/**
 * 客户类
 */
public class Client {
    
    
    public static void main(String[] args) {
    
    
        Coffee coffee = CoffeeFactory.createCoffee("american");
        System.out.println(coffee.getName());
    }
}

记录每一个学习瞬间

Acho que você gosta

Origin blog.csdn.net/qq_51601665/article/details/131052702
Recomendado
Clasificación