一本正经的扯淡:不要再尝试函数式编程了
作者 | Ilya Suzdalnitski
译者 | 刘雅梦
编辑 | 陈思
也许你曾听说过所谓的“函数式”编程,也许你甚至在想接下来是否要尝试一下。但是,函数式编程有很多缺陷,并不适用于现实项目的开发,并且会造成工作效率的下降。欲知详情,且听本文娓娓道来。【译者注:本篇采用了讽刺的写法,若急于知道真相,请拉至文末。】
现实世界中的企业级软件需要满足一系列复杂的、严格的、强制性的需求,这些需求与大量内嵌于软件解决方案中的抽象预期相关。换句话说,面向对象编程有助于程序员使用多种抽象机制,这些抽象机制完全能够满足企业的复杂需求。
import { filter, first, get } from 'lodash/fp';
const filterByType = type =>
filter( x => x.type === type );
const fruits = [
{ type: 'apple', price: 1.99 },
{ type: 'orange', price: 2.99 },
{ type: 'grape', price: 44.95 }
];
const getFruitPrice = type => fruits =>
fruits
|> filterByType(type)
|> first
|> get('price');
const getApplePrice = getFruitPrice('apple');
console.log('apple price', getApplePrice(fruits));
class Fruit {constructor(type, price) {this.type = type;this.price = price;}}class AbstractFruitFactory {make(type, price) {return new Fruit(type, price);}}class AppleFactory extends AbstractFruitFactory {make(price) {return super.make("apple", price);}}class OrangeFactory extends AbstractFruitFactory {make(price) {return super.make("orange", price);}}class GrapeFactory extends AbstractFruitFactory {make(price) {return super.make("grape", price);}}class FruitRepository {constructor() {this.fruitList = [];}locate(strategy) {return strategy.locate(this.fruitList);}put(fruit) {this.fruitList.push(fruit);}}class FruitLocationStrategy {constructor(fruitType) {this.fruitType = fruitType;}locate(list) {return list.find(x => x.type === this.fruitType);}}class FruitPriceLocator {constructor(fruitRepository, locationStrategy) {this.fruitRepository = fruitRepository;this.locationStrategy = locationStrategy;}locatePrice() {return this.fruitRepository.locate(this.locationStrategy).price;}}const appleFactory = new AppleFactory();const orangeFactory = new OrangeFactory();const grapeFactory = new GrapeFactory();const fruitRepository = new FruitRepository();fruitRepository.put(appleFactory.make(1.99));fruitRepository.put(orangeFactory.make(2.99));fruitRepository.put(grapeFactory.make(44.95));const appleLocationStrategy = new FruitLocationStrategy("apple");const applePriceLocator = new FruitPriceLocator(fruitRepository,appleLocationStrategy);const applePrice = applePriceLocator.locatePrice();console.log("apple", applePrice);
// 重构之前:
// calculator.js:
const isValidInput = text => true;
const btnAddClick = (aText, bText) => {
if (!isValidInput(aText) || !isValidInput(bText)) {
return;
}
}
// 重构之后:
// inputValidator.js:
export const isValidInput = text => true;
// calculator.js:
import { isValidInput } from './inputValidator';
const btnAddClick = (aText, bText, _isValidInput = isValidInput) => {
if (!_isValidInput(aText) || !_isValidInput(bText)) {
return;
}
}
// 重构之前:
public class CalculatorForm {
private string aText, bText;
private bool IsValidInput(string text) => true;
private void btnAddClick(object sender, EventArgs e) {
if ( !IsValidInput(bText) || !IsValidInput(aText) ) {
return;
}
}
}
// 重构之后:
public class CalculatorForm {
private string aText, bText;
private readonly IInputValidator _inputValidator;
public CalculatorForm(IInputValidator inputValidator) {
_inputValidator = inputValidator;
}
private void btnAddClick(object sender, EventArgs e) {
if ( !_inputValidator.IsValidInput(bText)
|| !_inputValidator.IsValidInput(aText) ) {
return;
}
}
}
public interface IInputValidator {
bool IsValidInput(string text);
}
public class InputValidator : IInputValidator {
public bool IsValidInput(string text) => true;
}
public class InputValidatorFactory {
public IInputValidator CreateInputValidator() => new InputValidator();
}
class CountryUserSelectionStrategy {
constructor(country) {
this.country = country;
}
isMatch(user) {
return user.country === this.country;
}
}
class UserSelector {
constructor(repository, userSelectionStrategy) {
this.repository = repository;
this.userSelectionStrategy = userSelectionStrategy;
}
selectUser() {
let user = null;
for (const u in users) {
if ( this.userSelectionStrategy.isMatch(u) ) {
user = u;
break;
}
}
return user;
}
}
const userRepository = new UserRepository();
const userInitializer = new UserInitializer();
userInitializer.initialize(userRepository);
const americanSelectionStrategy = new CountryUserSelectionStrategy('USA');
const americanUserSelector = new UserSelector(userRepository, americanSelectionStrategy);
const american = americanUserSelector.selectUser();
console.log('American', american);
SELECT * FROM Users WHERE Country=’USA’;
生产力 = 代码行数 x 修复 bug 数
代码行数 = 编码实践 = $$$ 纯利润 $$$
if (1 == '1') { doStuff();} else { // pure profit}
要获得更深入的解释,请参阅我的另一篇面向对象编程文章《上帝的恩惠》。
