1

Тема: Підскажіть паттерн обробки різних повідомлень і т.д.

Прів. Є купа повідомлень, кожне повідомлення має якийсь тип, і в залежності від типу повідомлення ми щось з ним робимо. Але є одна загальна риса цих повідомлень - всі вони додаються в один і той самий стек, і в проміжках між додаванням повідомлень в стек, потрібно показувати деяку картинку, котра повідомляє нам, що тіпо - будь-ласка, чекайте.
Також, перед додаванням повідомлення в стек, ми повинні почекати деякий час, і цей час залежить від довжини тексту в повідомленні, а якщо повідомлення не містить тексту, то ми чекаємо просто одну секунду.
Є повідомлення, котрі містять в собі лише картинку, в такому разі ми додаємо маленьку копію цієї картинки в стек, після чого зупиняємо весь цей конвеєр і збільшуємо іконку до розмірів оригінальної картинки, після цього, якщо користувач натисне на крестик, то ця збільшена іконка зникає і повідомлення надходять і далі.

А тепер проблема!
З самого початку кожне повідомлення я уявляв собі як окремий об'єкт, і тоді було все просто

foreach (var message in messages)
{

    // показуємо картинку "пліз, чекайте на наступне повідомлення"
    switch(message.type){
      case TEXT:
        //чекаємо деяку кількість часу
        // додаємо повідомлення в стек
      break;

     case IMAGE:
        //чекаємо деяку кількість часу
        // додаємо іконку в стек
        // збільшуємо іконку
        // stop = true
        // while(stop) {wait();}
        // якщо десь там натиснули на певну кнопку, то stop=false і конвеєр пішов далі
      break;
  }
  // ховаємо картинку "пліз, почекайте на наступне повідомлення"
  // чекаємо пів секунди, чи десь так, аби ця картинка не з'являлася відразу після приховування
}

Але тепер вияснилось, що є цілі черги з повідомлень одного типу, тобто 10 разів підряд буде надходити повідомлення одного й того самого типу (повідомлення з текстом), і я вирішив зробити от таку стуктуру повідомлення

class Message{
public string text;
public string pathToImage;
public string[] messages; // ось тут масив з текстів
}

І коли надходить повідомлення, що містить текст, то я маю просто перевірити кількість об'єктів в масиві string[] messages, ну і якщо там щось є, то треба всі ці повідомлення додати в стек, при цьому тре вставляти затримки перед додаванням кожного повідомлення.

Як то все краще зробити? В мене була от така структура

foreach(var m in messages){
switch(m.type){
case Type1:
break;

case Type2:
break;

case Type3:
break;}

// а от тут різний код, котрий не залежить від типу повідомлення, наприклад, кожне повідомлення треба додати в стек, от тут може бути код додавання в стек, тому що йому пофіг на тип того повідомлення
}

А от зараз мені треба якось запихнути цикл додавання повідомлення в блок case, і тре то все зробити якось супер-гарно, аби код не повторювався ніде, от вам теперішній код.
Як то все зробити, щоб було гарно і оптимізовано?

IEnumerator StartChat(List<MessageData> messages)
    {
       // Debug.Log("start chat");

        yield return new WaitForEndOfFrame();

        MessageController mc = null;
        GameObject go = null;
        RectTransform rectTrans = null;
        MessageImageController mic = null;

        float timeToWait = 0;
        int countToStop = 0;

        foreach (var message in messages)
        {
            MessageType type = message.type;
            countToStop++;
            //yield return new WaitForSeconds(0.5f);
            loaderToMove.transform.DOMoveX(loaderVisible.position.x, 0.2f);

            if (message.text.Length < 20)
                timeToWait = 1.5f;
            else if (message.text.Length >= 20)
                timeToWait = 2.5f;
            else if (message.text.Length >= 50)
                timeToWait = 3.5f;
            else if (message.text.Length >= 80)
                timeToWait = 4.5f;
            else timeToWait = 1;

            switch (type){
                case MessageType.TEXT:
                    //continue;

                    if (message.name != oldName)
                    {
                        oldName = message.name;
                        side = !side;
                    }

                    if (side)
                    {
                        go = Instantiate(leftMessage, Vector2.zero, Quaternion.identity) as GameObject;
                    }
                    else
                    {
                        go = Instantiate(rightMessage, Vector2.zero, Quaternion.identity) as GameObject;
                    }

                    mc = go.GetComponent<MessageController>();
                    mc.messageType = message.type;
                    mc.Text = "<b>" + message.name + "</b>: " + message.text;

                    yield return new WaitForSeconds(timeToWait);

                    go.transform.SetParent(content.transform);
                    RefreshTrans(go.transform);

                    mc.SetSide(side);

                    this.messages.Add(mc);
                    break;

                case MessageType.SYSTEM_CONNECTION_RESTORED:
                    //continue;
                    go = Instantiate(systemMessageConnectionR, Vector2.zero, Quaternion.identity) as GameObject;

                    yield return new WaitForSeconds(timeToWait);

                    go.transform.SetParent(content.transform);
                    RefreshTrans(go.transform);

                    this.messages.Add(mc);
                    break;

                case MessageType.IMAGE:
                    go = Instantiate(imageMessage, Vector2.zero, Quaternion.identity) as GameObject;
                    mic = go.GetComponent<MessageImageController>();
                    var spriteMini = Resources.Load<Sprite>(message.imagePath);
                    var spriteFull = Resources.Load<Sprite>(message.imagePath.Replace("mini", ""));
                    mic.FullSprite = spriteFull;
                    imageVwr.sprite = spriteFull;
                    mic.Image = spriteMini;
                    mc = mic;
                    stopChat = true;

                    yield return new WaitForSeconds(timeToWait);

                    go.transform.SetParent(content.transform);
                    RefreshTrans(go.transform);

                    ScaleImage(mic);

                    while (stopChat)
                    {
                        yield return new WaitForEndOfFrame();
                    }

                    this.messages.Add(mc);
                    break;

                case MessageType.BUTTON_SELECT_CHAR:
                    go = Instantiate(selectCharBtn, Vector2.zero, Quaternion.identity) as GameObject;
                    var mb = go.GetComponent<CanvasGroup>();
                    mb.DOFade(1, 3f);

                    yield return new WaitForSeconds(timeToWait);

                    go.transform.SetParent(content.transform);
                    RefreshTrans(go.transform);

                    this.messages.Add(mc);
                    break;

                case MessageType.SYSTEM_MESSAGE:
                    go = Instantiate(systemMessage, Vector2.zero, Quaternion.identity) as GameObject;

                    yield return new WaitForSeconds(timeToWait);

                    go.transform.SetParent(content.transform);
                    RefreshTrans(go.transform);

                    this.messages.Add(mc);
                    break;

                case MessageType.ADMIN_MESSAGE:
                    foreach(var str in message.messages)
                    {
                        go = Instantiate(adminMessage, Vector2.zero, Quaternion.identity) as GameObject;

                        mc = go.GetComponent<MessageController>();
                        mc.messageType = message.type;
                        string str1 = str.Replace("[b]", "<b>");
                        str1 = str1.Replace("[/b]", "</b>");
                        mc.Text = str1;

                    }

                    go.transform.SetParent(content.transform);
                    RefreshTrans(go.transform);

                    this.messages.Add(mc);
                    break;
            }                

            loaderToMove.transform.DOMoveX(loaderHidden.position.x, 0.2f);
            yield return new WaitForSeconds(0.6f);

        }
    }

2 Востаннє редагувалося Yola (03.02.2016 18:38:41)

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

Останній лістинг я не читав, бо мені вже забагато, але якщо ми програмуємо на ООП, то не потрібен нам switch.

Нам треба, що саме повідомлення могло сказати скільки чекати, нехай воно саме перевірить свої поля і підрахує час очікування. (Це для початку, потім можна ще ооп'ешніше зробити)

І ще, якщо в нас ООП, то публічними повинні бути методи, а не поля.

class Message{
public string text;
public string pathToImage;
public string[] messages; // ось тут масив з текстів
}

І не зовсім зрозуміла ця структура (класом я це не назву). Що означає кожне поле? Вони всі завжди заповнені?

Подякували: Regen, FakiNyan, quez3

3

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

оффтоп

Прихований текст

богі, який страшний код, та він геть не читабельний  :o

4

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

Regen написав:

оффтоп

Прихований текст

богі, який страшний код, та він геть не читабельний  :o

то пропонуйте свій варіант

5

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

FakiNyan написав:
Regen написав:

оффтоп

Прихований текст

богі, який страшний код, та він геть не читабельний  :o

то пропонуйте свій варіант

ну як мінімум розбити це все на енну кількість методів
і ще пораджу почитати ось цю книжку http://www.amazon.com/Clean-Code-Handbo … 0132350882

знову ж таки офтоп :)

6

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

Yola написав:

Останній лістинг я не читав, бо мені вже забагато, але якщо ми програмуємо на ООП, то не потрібен нам switch.

Нам треба, що саме повідомлення могло сказати скільки чекати, нехай воно саме перевірить свої поля і підрахує час очікування. (Це для початку, потім можна ще ооп'ешніше зробити)

І ще, якщо в нас ООП, то публічними повинні бути методи, а не поля.

class Message{
public string text;
public string pathToImage;
public string[] messages; // ось тут масив з текстів
}

І не зовсім зрозуміла ця структура (класом я це не назву). Що означає кожне поле? Вони всі завжди заповнені?


ну це тіпа яким може бути повідомлення, от якщо взяти всі типи повідомлень, то ця класна структура має поля під всі можливі дані, котрі може містити повідомлення, я там ще забув додати поле public MessageType type (це enum),  і от в XML'і йде опис повідомлень, якщо треба просто системне повідомлення, котре по суті унікальне, то класна структура буде просто містити потрібний type, і більше нічо не треба, якщо ж це буде стандартне повідомлення, котре містить лише текст, то type буде інший, і поле text буде містити інфу, якщо ж повідомлення - це картинка, то text буде пустим, а pathToImage буде містити інфу.

7

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

Regen написав:
FakiNyan написав:
Regen написав:

оффтоп

Прихований текст

богі, який страшний код, та він геть не читабельний  :o

то пропонуйте свій варіант

ну як мінімум розбити це все на енну кількість методів
і ще пораджу почитати ось цю книжку http://www.amazon.com/Clean-Code-Handbo … 0132350882

знову ж таки офтоп :)

ну так це ж чернетка, я от і питаю, як з неї зробити щось файне

8

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

Може тримати в json ?

9

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

VTrim написав:

Може тримати в json ?

то може ще й переписати то все на PHP?

10 Востаннє редагувалося VTrim (03.02.2016 19:21:11)

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

FakiNyan написав:
VTrim написав:

Може тримати в json ?

то може ще й переписати то все на PHP?

Мда.

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

можна попросити у когось тут допомогти для програмування на паскалі?

12

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

Єфросинія Некрадикабель, створіть окрему тему.

Подякували: koala, 0xDADA11C72

13

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

Зробив розрахунок затримки в самому повідомленні, тілько мені здалося, що ці два методи можна сміливо виключити з класу повідомлення, тому що зараз, якщо не передається ніякий аргумент, то повертається затримка для поля text, ну а якщо передається, то вже для аргументу час рахується (це потрібно в тому випадку, коли поле messages не пусте, і треба додавати купу повідомлень беручи тексти повідомлень з цього масиву, тоді я просто передаю елемент масиву як аргумент), але ж я можу так само передавати й поле text в якості аргументу, і тоді ці методи мона запихнути в якийсь клас, типу Utils, чи якось так.

public class MessageData  {
    [XmlAttribute("type")]
    public MessageType type;

    public string name { get; private set; }
    public string text { get; private set; }

    public string imagePath { get; private set; }

    public List<string> messages { get; private set; }

    public float TimeToWait(string str=null)
    {
        if(string.IsNullOrEmpty(str))
        {
            if(!string.IsNullOrEmpty(text))
            {
                return CalcTime(text);
            }
            else
            {
                return 1f;
            }
        }
        else
        {
            return CalcTime(str);
        }
    }

    private float CalcTime(string text)
    {
        if (text.Length < 20)
            return 1.5f;
        else if (text.Length >= 20)
            return 2.5f;
        else if (text.Length >= 50)
            return 3.5f;
        else return 4.5f;
    }
}

Ну і перетворив поля на параметри, аби брати можна було, а встановлювати не можна було, бо робити метод на кожне поле якось фу-фу-фу.

А от як позбутись switch'у я так і не зрозумів. Цей switch потрібен для розпізнавання типу повідомлення, в принципі можна було б обмазатись поліморфізмом з ніг до голови і використати тип dynamic (він дозволяє отримати об'єкт типу класа наслідника з об'єкту котрий має тип батьківського класу), тоді можна було б зробити так

    class A { }

    class B : A { }

    class C : A { }

    private void ShowClassName(A a)
    {
        Debug.Log("a class");
    }
    private void ShowClassName(B b)
    {
        Debug.Log("b class");
    }
    private void ShowClassName(C c)
    {
        Debug.Log("c class");
    }

    private void ShowClass()
    {
        A a = new A();
        A b = new B();
        A c = new C();

        dynamic aD = a;
        dynamic bD = b;
        dynamic cD = c;

        ShowClassName(aD);
        ShowClassName(bD);
        ShowClassName(cD);
    }

І кожне повідомлення оброблялося б по-своєму в спеціально зробленому для нього методі, але там, де я роблю це все, застаріла бібліотека (це я на c# пишу), і такі фокуси не пройдуть, тому я не бачу шляху, котрий дозволив би не використовувати switch.

Зараз основний метод виглядає от так

IEnumerator StartChat(List<MessageData> messages)
    {
       // Debug.Log("start chat");

        yield return new WaitForEndOfFrame();

        MessageController mc = null;
        GameObject go = null;
        RectTransform rectTrans = null;
        MessageImageController mic = null;

        float timeToWait = 0;
        int countToStop = 0;

        foreach (var message in messages)
        {
            MessageType type = message.type;
            countToStop++;
            //yield return new WaitForSeconds(0.5f);
            loaderToMove.transform.DOMoveX(loaderVisible.position.x, 0.2f);

            switch (type){
                case MessageType.TEXT:
                    //continue;

                    if (message.name != oldName)
                    {
                        oldName = message.name;
                        side = !side;
                    }

                    if (side)
                    {
                        go = Instantiate(leftMessage, Vector2.zero, Quaternion.identity) as GameObject;
                    }
                    else
                    {
                        go = Instantiate(rightMessage, Vector2.zero, Quaternion.identity) as GameObject;
                    }

                    mc = go.GetComponent<MessageController>();
                    mc.messageType = message.type;
                    mc.Text = "<b>" + message.name + "</b>: " + message.text;

                    yield return new WaitForSeconds(message.TimeToWait());

                    go.transform.SetParent(content.transform);
                    RefreshTrans(go.transform);

                    mc.SetSide(side);

                    this.messages.Add(mc);
                    break;

                case MessageType.SYSTEM_CONNECTION_RESTORED:
                    //continue;
                    go = Instantiate(systemMessageConnectionR, Vector2.zero, Quaternion.identity) as GameObject;

                    yield return new WaitForSeconds(message.TimeToWait());

                    go.transform.SetParent(content.transform);
                    RefreshTrans(go.transform);

                    this.messages.Add(mc);
                    break;

                case MessageType.IMAGE:
                    go = Instantiate(imageMessage, Vector2.zero, Quaternion.identity) as GameObject;
                    mic = go.GetComponent<MessageImageController>();
                    var spriteMini = Resources.Load<Sprite>(message.imagePath);
                    var spriteFull = Resources.Load<Sprite>(message.imagePath.Replace("mini", ""));
                    mic.FullSprite = spriteFull;
                    imageVwr.sprite = spriteFull;
                    mic.Image = spriteMini;
                    mc = mic;
                    stopChat = true;

                    yield return new WaitForSeconds(message.TimeToWait());

                    go.transform.SetParent(content.transform);
                    RefreshTrans(go.transform);

                    ScaleImage(mic);

                    while (stopChat)
                    {
                        yield return new WaitForEndOfFrame();
                    }

                    this.messages.Add(mc);
                    break;

                case MessageType.BUTTON_SELECT_CHAR:
                    go = Instantiate(selectCharBtn, Vector2.zero, Quaternion.identity) as GameObject;
                    var mb = go.GetComponent<CanvasGroup>();
                    mb.DOFade(1, 3f);

                    yield return new WaitForSeconds(message.TimeToWait());

                    go.transform.SetParent(content.transform);
                    RefreshTrans(go.transform);

                    this.messages.Add(mc);
                    break;

                case MessageType.SYSTEM_MESSAGE:
                    go = Instantiate(systemMessage, Vector2.zero, Quaternion.identity) as GameObject;

                    yield return new WaitForSeconds(message.TimeToWait());

                    go.transform.SetParent(content.transform);
                    RefreshTrans(go.transform);

                    this.messages.Add(mc);
                    break;

                case MessageType.ADMIN_MESSAGE:
                    if (message.messages!=null)
                    {
                        foreach (var str in message.messages)
                        {
                            go = Instantiate(adminMessage, Vector2.zero, Quaternion.identity) as GameObject;

                            mc = go.GetComponent<MessageController>();
                            mc.messageType = message.type;
                            string str1 = str.Replace("[b]", "<b>");
                            str1 = str1.Replace("[/b]", "</b>");
                            mc.Text = str1;

                            yield return new WaitForSeconds(message.TimeToWait(str));

                            go.transform.SetParent(content.transform);
                            RefreshTrans(go.transform);
                            mc.SetSide(true);

                            this.messages.Add(mc);
                        }
                    }
                    else
                    {
                        go = Instantiate(adminMessage, Vector2.zero, Quaternion.identity) as GameObject;

                        mc = go.GetComponent<MessageController>();
                        mc.messageType = message.type;
                        string str1 = message.text.Replace("[b]", "<b>");
                        str1 = str1.Replace("[/b]", "</b>");
                        mc.Text = str1;

                        yield return new WaitForSeconds(message.TimeToWait());

                        go.transform.SetParent(content.transform);
                        RefreshTrans(go.transform);
                        this.messages.Add(mc);
                    }
                    break;
            }                

            loaderToMove.transform.DOMoveX(loaderHidden.position.x, 0.2f);
            yield return new WaitForSeconds(0.6f);
        }
    }

14

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

Як цей if має працювати?

        if (text.Length < 20)
            return 1.5f;
        else if (text.Length >= 20)
            return 2.5f;
        else if (text.Length >= 50)
            return 3.5f;
        else return 4.5f;

адже він тотожний до

        if (text.Length < 20)
            return 1.5f;
        else
            return 2.5f;
Подякували: iovchynnikov, koala, FakiNyan, leofun014

15 Востаннє редагувалося FakiNyan (04.02.2016 16:29:30)

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

Yola написав:

Як цей if має працювати?

        if (text.Length < 20)
            return 1.5f;
        else if (text.Length >= 20)
            return 2.5f;
        else if (text.Length >= 50)
            return 3.5f;
        else return 4.5f;

адже він тотожний до

        if (text.Length < 20)
            return 1.5f;
        else
            return 2.5f;

ой, там тре

        if (text.Length < 20)
            return 1.5f;
        else if (text.Length >= 80)
            return 4.5f;
        else if (text.Length >= 50)
            return 3.5f;
        else return 2.5f;

upd: якось це падібільнаму, так краще

 if (text.Length >= 80)
            return 4.5f;
        else if (text.Length >= 50)
             return 3.5f;
        else if(text.length>=20)
             return 2.5f;
        else return 1.5f;

16

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

Запитав у одного знайомого москаля, і той нагадав мені, що то таке - ООП.
Значить, зроблю так - створю базовій клас для всіх повідомлень, котрий буде мати метод Draw(), і в цьому методі буде зосереджена вся потрібна інфа для додавання повідомлення в стек і т.д., тоді й справді ніякий switch не треба буде.

Бай зе вей, якщо ось такий підхід зветься ООП, тобто, коли дані і логіка, що працює з цими даними, зосереджені в одному об'єкті, то як зветься підхід, коли в метод передаються дані, і вже там вирішується, що з ними робити?

17

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

Тижпрограміст. Що за запитання такі? Викинь диплома.

18

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

Invader написав:

Тижпрограміст. Що за запитання такі? Викинь диплома.

нєєє! як же так! я ж без диплома нічо заробити не зможу!!!

19

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

Invader написав:

Тижпрограміст. Що за запитання такі? Викинь диплома.

З яких це пір шарпомакаки стали програмістами?

20 Востаннє редагувалося 0xDADA11C7 (05.02.2016 00:16:42)

Re: Підскажіть паттерн обробки різних повідомлень і т.д.

VTrim написав:

шарпомакаки

я в своєму житті бачив лише 2 шарпомакаки - Faraon та один вікіп**ор(в хорошому сенсі цього слова), він мабуть є хорошою людиною, розуміється на здобутках української вікіспільноти, та краще б жив в Ізраїлі та опікувався тамтешньою вікіпедією. Наразі ви є модератором, тому не чіпайте Трусіка, бо це не чесна гра.

Подякували: koala, leofun012