分解方法/函数只做一件事被认为是一种很好的做法,因为它可以带来更可维护和可读的代码,但在许多情况下会增加操作数量。如何实现两者即。最佳操作数,同时仍保持可读性/可维护性?
如该虚拟示例所示。我想找到字符串中
J
的计数,但也想检查所有正整数的加法是否为 even
或 odd
。这 2 个不同任务的两种单独方法可带来出色的可读性,但会增加 n
的操作数量,其中 n
是输入字符串的大小。将它们组合在一个方法中会导致可读性非常低,但会减少操作数量。
class UserText{
constructor(userProvidedText){
this.content = userProvidedText;
}
_findCharCount(char){
let count = 0;
for (let i = 0; i < this.content.length; i++) {
if (this.content[i] === char) {
count++;
}
}
return count
}
_isDigit(char) {
return !isNaN(parseInt(char));
}
// Excellent Readability and maintainability
findLetterCount(char){
return this._findCharCount(char)
}
// Excellent Readability and maintainability
CheckIfDigitsAdditionEven(){
let count = 0;
for (let i = 0; i < this.content.length; i++) {
console.log(this.content[i])
if (!this._isDigit(this.content[i])){
continue
}
count+=parseInt(this.content[i]);
}
if (count % 2 === 0){
return true
}
return false
}
// Combining functionalities in 1 function . Not readable. Not maintainable But time complexity is decreased.
CheckIfDigitsAdditionEvenAndCountLetter(char){
let count1 = 0;
let count2 = 0;
let res1 = false;
for (let i = 0; i < this.content.length; i++) {
if (this.content[i] === char) {
count2++;
}
if (this._isDigit(this.content[i])){
count1+=parseInt(this.content[i]);
}
}
if (count1 % 2 === 0){
res1 = true
}
return [res1, count2]
}
}
ut = new UserText("SOME..STRING..12311.HHIIJJJJKKKLL ")
/*
Breaking up functions and using them one at a time . One method , one purpose..
Maintainable and readable but iterates by 2n.
*/
JCount=ut.findLetterCount("J")
evenCheck=ut.CheckIfDigitsAdditionEven()
/*
Using 1 function for the task . One method , multi-purposed..
Maintainable and readable is very low but iterates by "n" only .
*/
cr=ut.CheckIfDigitsAdditionEvenAndCountLetter("J")
// Some custom logic here .
console.log(JCount, evenCheck)
console.log(cr[0], cr[1])
首先,设计模型时考虑性能问题是好的,但应该避免过早优化。
其次,在我看来,OP 的代码既不干净/精简,也不可维护,正如 OP 声称的那样。并且所有伪私有注释原型方法的实现已经开始变得一团糟。第三,OP的
CheckIfDigitsAdditionEvenAndCountLetter
方法混合了两个任务,无论如何都必须单独实现......例如如
hasEvenTotalDigitCount
和
getTotalLetterCountFor
。因此,OP 应该编写很多辅助/实用函数,每个函数一次只做一件事。然后,这些助手会被极少数且只有真正必要的方法重新使用,OP 希望模型具有特色。
OP 提供的更好可读、可维护的版本可能类似于以下示例代码......
// e.g. ... `UserText` module with ...
//
// - locally scoped helper functions
// - and a single class export.
//
// - each helper function might/should
// get exported as well for testing.
function isEvenNumber(value) {
return (value % 2 === 0);
}
function isDigit(value) {
return (/^\p{N}$/u).test(String(value));
}
function isLetter(value) {
return (/^\p{L}$/u).test(String(value));
}
function getTotalDigitCount(text) {
return text.match(/\p{N}/gu);
}
function getTotalLetterCount(text) {
return text.match(/\p{L}/gu);
}
function getTotalMatchCount(text, query) {
return text.match(
RegExp(
query.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'
)
)?.length ?? 0;
}
/*export */class UserText{
#text;
constructor(value) {
// - always ensure a protected string value.
this.#text = String(value);
}
get value() {
// - helps ensuring the immutability of
// the initially passed user text value.
return this.#text;
}
getTotalDigitCountFor(value) {
value = String(value);
return isDigit(value) ? getTotalMatchCount(this.#text, value) : 0;
}
getTotalLetterCountFor(value) {
value = String(value);
return isLetter(value) ? getTotalMatchCount(this.#text, value) : 0;
}
hasEvenTotalDigitCount() {
const totalCount = getTotalDigitCount(this.#text);
return (totalCount !== 0) && isEvenNumber(totalCount);
}
hasEvenTotalLetterCount() {
const totalCount = getTotalLetterCount(this.#text);
return (totalCount !== 0) && isEvenNumber(totalCount);
}
}
// end of `UserText` module.
// e.g.
/* import { UserText } from './UserText.js'; */
const userText = new UserText("SOME..STRING..12311.HHIIJJJJKKKLL ");
const totalCountOfUpper_J = userText.getTotalLetterCountFor('J');
const hasEvenTotalDigitCount = userText.hasEvenTotalDigitCount();
console.log({
totalCountOfUpper_J,
hasEvenTotalDigitCount,
});
// attempt of manipulating the text value.
userText.value = 'foo, bar, baz';
console.log({
userText,
'userText.value': userText.value,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }