Diretório de artigos
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 SimpleCoffeeFactory
do 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.
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.
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.
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());
}
}
记录每一个学习瞬间