Господа, всем известно что нагромождение конструкций if-else есть признак плохого тона. Попробуем обойтись без их использования в некоторых ситуациях.
If-else в фабричном методе.
Для примера есть стандартная реализация паттерна "Фабричный метод", создающая объекты в зависимости от некоторого ключа.
package com.bssys.blog.example;
Тут присутcnвует громоздкая конструкция if-else. Как избавиться от нее?
Использовать HashMap.
Фактически введем динамический if. Таким образом класс Factory будет выглядеть следующим образом:
Использовать enum с абстрактным методом.
В таком случае наш фабричный метод переродится в следующее:
Есть еще один способ обойтись без if используя reflection, но я не приветствую такой подход. Если хотите динамичности то берите наверное другой язык, а не java.
If-else в фабричном методе.
Для примера есть стандартная реализация паттерна "Фабричный метод", создающая объекты в зависимости от некоторого ключа.
package com.bssys.blog.example;
public class App {
private Factory factory;
public App() {
factory = new Factory();
}
public void onMessage(String message) {
Product product = factory.createProduct(message);
product.action();
}
public static void main(String[] args) {
App app = new App();
app.onMessage("A");
app.onMessage("B");
}
}
interface Product {
public void action();
}
class ConcreteProductA implements Product {
public void action() {
System.out.println("ConcreteProductA");
}
}
class ConcreteProductB implements Product {
public void action() {
System.out.println("ConcreteProductB");
}
}
class Factory {
Product createProduct(String key) {
Product product = null;
if ("A".equals(key)) {
product = new ConcreteProductA();
} else if ("B".equals(key)) {
product = new ConcreteProductB();
}
return product;
}
}
Тут присутcnвует громоздкая конструкция if-else. Как избавиться от нее?
Использовать HashMap.
Фактически введем динамический if. Таким образом класс Factory будет выглядеть следующим образом:
class Factory {
private Map<String, Product> factoryMap;
public Factory() {
factoryMap = new HashMap<String, Product>();
factoryMap.put("A", new ConcreteProductA());
factoryMap.put("B", new ConcreteProductB());
}
Product createProduct(String key) {
Product product = factoryMap.get(key);
return product;
}
}
Тут мы немного сломали ожидаемое поведение, так как фабричный метод будет возвращать одни и теже объекты. Иногда это даже хорошо. Но тем не менее чтобы ожидаемое поведение было одинаковым введем интерфейс фабрики которая будет создавать конкретные продукты. И отрефакторим код:
package com.bssys.blog.example;
import java.util.HashMap;
import java.util.Map;
public class App {
private CommonFactory factory;
public App() {
factory = new CommonFactory();
}
public void onMessage(String message) {
Product product = factory.createProduct(message);
product.action();
}
public static void main(String[] args) {
App app = new App();
app.onMessage("A");
app.onMessage("B");
}
}
interface Product {
public void action();
}
class ConcreteProductA implements Product {
public void action() {
System.out.println("ConcreteProductA");
}
}
class ConcreteProductB implements Product {
public void action() {
System.out.println("ConcreteProductB");
}
}
interface Factory{
Product createProduct();
}
class ConcreteProductAFactory implements Factory{
public Product createProduct() {
return new ConcreteProductA();
}
}
class ConcreteProductBFactory implements Factory{
public Product createProduct() {
return new ConcreteProductB();
}
}
class CommonFactory {
private Map<String, Factory> factoryMap;
public CommonFactory() {
factoryMap = new HashMap<String, Factory>();
factoryMap.put("A", new ConcreteProductAFactory());
factoryMap.put("B", new ConcreteProductBFactory());
}
Product createProduct(String key) {
Factory factory = factoryMap.get(key);
return factory.createProduct();
}
}
Уже лучше. Мы выделили интерфейс фабрики. Теперь у нас есть класс CommonFactory, который по сути является реестром всех объектов. Теперь если подключить мощь Spring мы могли бы вынести наш HashMap в конфиг, и управлять поведением не перекомпилируя наш код. Как вы видите мы нагенерили много кода. И хотя это правильный подход в java, есть немного другой способ избавиться от if.Использовать enum с абстрактным методом.
enum Type {
A {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
},
B {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
};
public abstract Product createProduct();
}
В таком случае наш фабричный метод переродится в следующее:
class Factory {
public Product createProduct(String key) {
Type valueOf = Type.valueOf(key);
return valueOf.createProduct();
}
}
Тут конечно тоже есть неявный динамический if при выполнении операции valueOf, но все равно выглядит элегантно.Есть еще один способ обойтись без if используя reflection, но я не приветствую такой подход. Если хотите динамичности то берите наверное другой язык, а не java.
Комментариев нет:
Отправить комментарий