Як пазбегнуць дублявання кода пры выкананні аперацыі на розных уласцівасцяў аб'екта

Нядаўна я сутыкнуўся з праблемай, якая прымусіла мяне думаць у колах. Выкажу здагадку, што ў мяне ёсць аб'ект тыпу O са ўласцівасцямі у.а. і O.B. Таксама выкажу здагадку, што ў мяне ёсць калекцыя асобнікаў тыпу O, дзе у.а. і O.B вызначаны для кожнага асобніка.

Зараз выкажам здагадку, што мне трэба выканаць некаторыя аперацыі (напрыклад, сартаванне) на калекцыю асобнікаў O з дапамогай альбо у.е або O.B, але не як у любы момант часу. Маё арыгінальнае рашэнне заключаецца ў наступным.

Прыклад - толькі для дэманстрацыі, а не код прадукцыі:

public class O {
    int A;
    int B;
}

public static class Utils {
    public static void SortByA (O[] collection) {
       //Sort the objects in the collection using O.A as the key. Note: this is custom sorting logic, so it is not simply a one-line call to a built-in sort method.
    }

    public static void SortByB (O[] collection) {
       //Sort the objects in the collection using O.B as the key. Same logic as above.
    }
}

Тое, што я хацеў бы зрабіць гэта ...

public static void SortAgnostic (O[] collection, FieldRepresentation x /* some non-bool, non-int variable representing whether to chose O.A or O.B as the sorting key */) {
   //Sort by whatever "x" represents...
}

... але і стварэнне новых, высока пэўны тып, які ў мяне будзе падтрымліваць толькі, каб пазбегнуць дублявання некалькі радкоў кода здаецца, непатрэбнымі мне. Можа быць, я няправільна на што (і я ўпэўнены, што нехта мяне паправіць, калі гэта зацвярджэнне няправільна: D), але гэта мая бягучая думка, тым не менш.

Пытанне: Які найлепшы спосаб рэалізацыі гэтага метаду? Логіка, што я павінен рэалізаваць цяжка разбіць на больш дробныя метады, так як ён ужо дастаткова аптымізаваны. У аснове гэтага пытання з'яўляецца той факт, што мне трэба выканаць тую ж самую аперацыю з выкарыстаннем розных уласцівасцяў аб'екта. Я хацеў бы застацца ў баку ад выкарыстання кодаў/сцягоў/і г.д .. у сігнатуры метады , калі гэта магчыма , так што рашэнне можа быць гэтак жа надзейна, як гэта магчыма.

Note: When answering this question, please approach it from an algorithmic point of view. I am aware that some language-specific features may be suitable alternatives, but I have encountered this problem before and would like to understand it from a relatively language-agnostic viewpoint. Also, please do not constrain responses to sorting solutions only, as I have only chosen it as an example. The real question is how to avoid code duplication when performing an identical operation on two different properties of an object.

3
Увогуле, вы, здаецца, хочаце Кампаратар ( для Java, па меншай меры). Ці вы хочаце выкарыстоўваць Reflection (які з'яўляецца даволі канкрэтным мовай).
дададзена аўтар Dukeling, крыніца
Увогуле, вы, здаецца, хочаце Кампаратар ( для Java, па меншай меры). Ці вы хочаце выкарыстоўваць Reflection (які з'яўляецца даволі канкрэтным мовай).
дададзена аўтар Dukeling, крыніца
Я адчуваю, што ваша праблема звязана з больш моўнымі магчымасцямі. Я не разумею «алгарытмічнай пункту гледжання». Адзіная логіка, што ёсць, што адбываецца ў вашым метадзе сартавання. Калі вы не хочаце, каб дадаць сцягі, каб выбраць ўласцівасць для выкарыстання, вы можаце выкарыстоўваць ананімны ўнутраны клас (у выпадку Java) або убудаваныя функцыі (у выпадку Javascript), каб ваш метад сартавання быць агностыку.
дададзена аўтар Seeta Somagani, крыніца
Я адчуваю, што ваша праблема звязана з больш моўнымі магчымасцямі. Я не разумею «алгарытмічнай пункту гледжання». Адзіная логіка, што ёсць, што адбываецца ў вашым метадзе сартавання. Калі вы не хочаце, каб дадаць сцягі, каб выбраць ўласцівасць для выкарыстання, вы можаце выкарыстоўваць ананімны ўнутраны клас (у выпадку Java) або убудаваныя функцыі (у выпадку Javascript), каб ваш метад сартавання быць агностыку.
дададзена аўтар Seeta Somagani, крыніца
@seeta - Дзякуй за ваш каментар. Пад «алгарытмічнай пункту гледжання» Я проста меў на ўвазе, што я хацеў бы вырашыць гэтую праблему праз некалькі праектаў, з якімі я працую (напрыклад, JavaScript з JQuery, C#, Java і г.д.). Кожны з іх мае розныя функцыі, якія маглі б дапамагчы, але я хацеў бы ведаць «найменшага агульнага назоўніка» рашэнне, якое можа быць выкарыстана ў адносінах да самому вялікаму ліку моў, без рэзкіх зменаў.
дададзена аўтар jtlovetteiii, крыніца
@seeta - Дзякуй за ваш каментар. Пад «алгарытмічнай пункту гледжання» Я проста меў на ўвазе, што я хацеў бы вырашыць гэтую праблему праз некалькі праектаў, з якімі я працую (напрыклад, JavaScript з JQuery, C#, Java і г.д.). Кожны з іх мае розныя функцыі, якія маглі б дапамагчы, але я хацеў бы ведаць «найменшага агульнага назоўніка» рашэнне, якое можа быць выкарыстана ў адносінах да самому вялікаму ліку моў, без рэзкіх зменаў.
дададзена аўтар jtlovetteiii, крыніца

8 адказы

<�Моцны> «Рэальны пытанне заключаецца ў тым, каб пазбегнуць дублявання кода пры выкананні ідэнтычную аперацыі на двух розных уласцівасцяў аб'екта.»

Гэта вельмі добрае пытанне, як узнікае такая сітуацыя ўвесь час. Я думаю, адзін з лепшых спосабаў справіцца з гэтай сітуацыяй, каб выкарыстоўваць наступны шаблон.

public class O {
    int A;
    int B;
}

public doOperationX1() {
   doOperationX(something to indicate which property to use);
}

public doOperationX2() {
   doOperationX(something to indicate which property to use);
}
private doOperationX(input ) {
    //actual work is done here
}

У гэтай мадэлі, фактычная рэалізацыя ажыццяўляецца ў прыватным метадзе, які называецца грамадскімі метадамі, з некаторай дадатковай інфармацыяй. Напрыклад, у дадзеным выпадку, гэта можа быць doOperationX (A), або doOperationX (B), ці нешта ў гэтым родзе.

Мае развагі: На мой погляд, гэтая мадэль з'яўляецца аптымальным, так як яна забяспечвае два асноўных патрабаванні:

  1. Ён падтрымлівае адкрыты інтэрфейс апісальным і ясна, як ён трымае аперацыі паасобку, і пазбягае сцягоў і г.д., якія вы згадалі ў вашым пасце. Гэта добра для кліента.

  2. З пункту гледжання рэалізацыі, гэта прадухіляе дубляванне, так як яна знаходзіцца ў адным месцы. Гэта добра для развіцця.

2
дададзена

<�Моцны> «Рэальны пытанне заключаецца ў тым, каб пазбегнуць дублявання кода пры выкананні ідэнтычную аперацыі на двух розных уласцівасцяў аб'екта.»

Гэта вельмі добрае пытанне, як узнікае такая сітуацыя ўвесь час. Я думаю, адзін з лепшых спосабаў справіцца з гэтай сітуацыяй, каб выкарыстоўваць наступны шаблон.

public class O {
    int A;
    int B;
}

public doOperationX1() {
   doOperationX(something to indicate which property to use);
}

public doOperationX2() {
   doOperationX(something to indicate which property to use);
}
private doOperationX(input ) {
    //actual work is done here
}

У гэтай мадэлі, фактычная рэалізацыя ажыццяўляецца ў прыватным метадзе, які называецца грамадскімі метадамі, з некаторай дадатковай інфармацыяй. Напрыклад, у дадзеным выпадку, гэта можа быць doOperationX (A), або doOperationX (B), ці нешта ў гэтым родзе.

Мае развагі: На мой погляд, гэтая мадэль з'яўляецца аптымальным, так як яна забяспечвае два асноўных патрабаванні:

  1. Ён падтрымлівае адкрыты інтэрфейс апісальным і ясна, як ён трымае аперацыі паасобку, і пазбягае сцягоў і г.д., якія вы згадалі ў вашым пасце. Гэта добра для кліента.

  2. З пункту гледжання рэалізацыі, гэта прадухіляе дубляванне, так як яна знаходзіцца ў адным месцы. Гэта добра для развіцця.

2
дададзена

«... але і стварэнне новых, высока пэўны тып, які ў мяне будзе падтрымліваць толькі, каб пазбегнуць дублявання некалькі радкоў кода, здаецца непатрэбным мне»

Вось чаму вы павінны выкарыстоўваць наяўныя інструменты, такія як рамкі ці іншы памылка друку кодавых бібліятэк, якія забяспечваюць Запытаны вамі рашэнне.

Калі нейкі механізм з'яўляецца агульным азначае, што ён можа быць перанесены на больш высокі ўзровень абстракцыі. Калі вы не можаце знайсці правільнае рашэнне паспрабаваць стварыць уласны. Падумайце пра вынік аперацыі, як не частка функцыянальнасці класа. Сартаванне толькі асаблівасць, што, чаму гэта не павінна быць часткай вашага класа з самага пачатку. Старайцеся, каб клас як мага больш простым.

Не хвалюйцеся, заўчасныя аб тым сэнсе, што нешта маленькае проста таму, што гэта мала. Фокус на канчатковым выкарыстанні гэтага. Калі вы выкарыстоўваеце вельмі часта адзін тып сартавання проста стварыць вызначэнне яго для яго паўторнага выкарыстання. Вам не трэба трэба стварыць клас utill, а затым выклікаць яго. Часам базавая функцыянальнасць складзена ў utill класа дастаткова справядліва.

Я мяркую, што вы карыстаецеся Java:

У вашым выпадку пухіры быў ужо рэалізаваны ў асобе калекцыя # сартавання (Спіс, кампаратар) .

Для поўнага запаўнення яго можна стварыць тып Enum, якія рэалізуюць інтэрфейс Comparator з наканаваных тыпамі сартавання.

0
дададзена

«... але і стварэнне новых, высока пэўны тып, які ў мяне будзе падтрымліваць толькі, каб пазбегнуць дублявання некалькі радкоў кода, здаецца непатрэбным мне»

Вось чаму вы павінны выкарыстоўваць наяўныя інструменты, такія як рамкі ці іншы памылка друку кодавых бібліятэк, якія забяспечваюць Запытаны вамі рашэнне.

Калі нейкі механізм з'яўляецца агульным азначае, што ён можа быць перанесены на больш высокі ўзровень абстракцыі. Калі вы не можаце знайсці правільнае рашэнне паспрабаваць стварыць уласны. Падумайце пра вынік аперацыі, як не частка функцыянальнасці класа. Сартаванне толькі асаблівасць, што, чаму гэта не павінна быць часткай вашага класа з самага пачатку. Старайцеся, каб клас як мага больш простым.

Не хвалюйцеся, заўчасныя аб тым сэнсе, што нешта маленькае проста таму, што гэта мала. Фокус на канчатковым выкарыстанні гэтага. Калі вы выкарыстоўваеце вельмі часта адзін тып сартавання проста стварыць вызначэнне яго для яго паўторнага выкарыстання. Вам не трэба трэба стварыць клас utill, а затым выклікаць яго. Часам базавая функцыянальнасць складзена ў utill класа дастаткова справядліва.

Я мяркую, што вы карыстаецеся Java:

У вашым выпадку пухіры быў ужо рэалізаваны ў асобе калекцыя # сартавання (Спіс, кампаратар) .

Для поўнага запаўнення яго можна стварыць тып Enum, якія рэалізуюць інтэрфейс Comparator з наканаваных тыпамі сартавання.

0
дададзена

Праблема можа быць зменшана да атрымання значэння названага поля ад гэтага аб'екта, так што можна выкарыстоўваць для сартавання мэтаў, або,

TField getValue(TEntity entity, string fieldName)
{
   //Return value of field "A" from entity,
   //implementation depends on language of choice, possibly with 
   //some sort of reflection support
}

Гэты метад можа быць выкарыстаны для замены параўнанняў у алгарытме сартавання,

if (getValue(o[i], "A")) > getValue(o[j], "A"))
{
    swap(i, j);
}

Імя поля можа быць параметризованным, так як,

public static void SortAgnostic (O[] collection, string fieldName) 
{
    if (getValue(collection[i], fieldName)) > getValue(collection[j], fieldName))
    {
        swap(i, j);
    }

    ...
}

які можна выкарыстоўваць як SortAgnostic (збор, "A") .

У некаторых мовах дазваляюць выказаць поле ў больш вытанчаным спосабам,

public static void SortAgnostic (O[] collection, Expression fieldExpression) 
{
    if (getValue(collection[i], fieldExpression)) > 
        getValue(collection[j], fieldExpression))
    {
        swap(i, j);
    }

    ...
}

which you can use like SortAgnostic(collection, entity => entity.A).

І яшчэ адзін варыянт можа быць перадае паказальнік на функцыю, якая будзе вяртаць значэнне поля неабходна,

public static void SortAgnostic (O[] collection, Function getValue) 
{
    if (getValue(collection[i])) > getValue(collection[j]))
    {
        swap(i, j);
    }
    ...
}

якая даецца функцыяй,

TField getValueOfA(TEntity entity)
{
    return entity.A;
}

і перадаць яго як SortAgnostic (збор, getValueOfA) .

0
дададзена

Праблема можа быць зменшана да атрымання значэння названага поля ад гэтага аб'екта, так што можна выкарыстоўваць для сартавання мэтаў, або,

TField getValue(TEntity entity, string fieldName)
{
   //Return value of field "A" from entity,
   //implementation depends on language of choice, possibly with 
   //some sort of reflection support
}

Гэты метад можа быць выкарыстаны для замены параўнанняў у алгарытме сартавання,

if (getValue(o[i], "A")) > getValue(o[j], "A"))
{
    swap(i, j);
}

Імя поля можа быць параметризованным, так як,

public static void SortAgnostic (O[] collection, string fieldName) 
{
    if (getValue(collection[i], fieldName)) > getValue(collection[j], fieldName))
    {
        swap(i, j);
    }

    ...
}

які можна выкарыстоўваць як SortAgnostic (збор, "A") .

У некаторых мовах дазваляюць выказаць поле ў больш вытанчаным спосабам,

public static void SortAgnostic (O[] collection, Expression fieldExpression) 
{
    if (getValue(collection[i], fieldExpression)) > 
        getValue(collection[j], fieldExpression))
    {
        swap(i, j);
    }

    ...
}

which you can use like SortAgnostic(collection, entity => entity.A).

І яшчэ адзін варыянт можа быць перадае паказальнік на функцыю, якая будзе вяртаць значэнне поля неабходна,

public static void SortAgnostic (O[] collection, Function getValue) 
{
    if (getValue(collection[i])) > getValue(collection[j]))
    {
        swap(i, j);
    }
    ...
}

якая даецца функцыяй,

TField getValueOfA(TEntity entity)
{
    return entity.A;
}

і перадаць яго як SortAgnostic (збор, getValueOfA) .

0
дададзена

Просты спосаб наблізіцца да гэтага, я думаю, засвойваць паводзіны выбару поля сартавання ў клас O сам. Такім чынам, рашэнне можа быць ад мовы.

Рэалізацыя ў Java можа выкарыстоўваць абстрактны клас для O , дзе мэта абстрактнага метаду getSortField() будзе вяртаць поля для сартавання. Усё, што логіка выкліку трэба будзе зрабіць, гэта рэалізаваць абстрактны метад, які вяртае патрэбнае поле.

O o = new O() {
    public int getSortField() {
        return A;
    }
};
0
дададзена

Просты спосаб наблізіцца да гэтага, я думаю, засвойваць паводзіны выбару поля сартавання ў клас O сам. Такім чынам, рашэнне можа быць ад мовы.

Рэалізацыя ў Java можа выкарыстоўваць абстрактны клас для O , дзе мэта абстрактнага метаду getSortField() будзе вяртаць поля для сартавання. Усё, што логіка выкліку трэба будзе зрабіць, гэта рэалізаваць абстрактны метад, які вяртае патрэбнае поле.

O o = new O() {
    public int getSortField() {
        return A;
    }
};
0
дададзена