#c_sharp #ооп
Задумался как сделать логичнее (правильнее). Есть два класса: один ставит лайки в нём два метода лайки по тэгу и лайки по геолокации, второй подписывается в нём тоже два метода подписываться по тэгу и по геолокации. Получается так, что у меня практически полностью дублируется один и тот же код в этих методах и классах. Разница в коде буквально в паре полей. Т.е. очень не удобно когда что-то меняешь, приходится менять всё тоже самое ещё в 3х методах. Понимаю, что можно было бы сделать один класс с одним методом например: _work.Run(param1,param2,param3 ...); , но думаю это потом негативно отразится при глобальном расширении проекта. А я хочу сделать два класса, что логичнее на мой взгляд и потом проще для понимания. _like.Run(param1,param2,param3 ...) и _subscribe.Run(param1,param2,param3 ...) но при этом что бы код методов не дублировался в каждом классе. UPD Запуск из формы try { //обратите внимание на передачу токена отмены, и экземпл. прогресса Task.Factory.StartNew(() => { //new thread if (radioButton1.Checked == true) { if (radioButton3.Checked == true) { _like.Tags(tag, time_wait, limit, filters, cancelToken); } if (radioButton4.Checked == true) { _like.Geolocation(geonumber, time_wait, limit, filters, cancelToken); } } if (radioButton6.Checked == true) { if (radioButton3.Checked == true) { //подписка по тэгу _subscribe.Tags(tag, time_wait, limit, filters, cancelToken); } if (radioButton4.Checked == true) { _subscribe.Geolocation(geonumber, time_wait, limit, filters, cancelToken); } } }); } catch (OperationCanceledException) { Console.WriteLine("Задача отменена."); } catch (Exception ex) { MessageBox.Show("В задаче произошла ошибка: " + ex, "Threads error", MessageBoxButtons.OK, MessageBoxIcon.Error); } класс Subscribe class Subscribe { String filter_view_in_msg_box = "без фильтров"; private IWebDriver _driver; private ControlFormProgramm _controlFormProgramm; public Subscribe(IWebDriver driver, ControlFormProgramm controlFormProgramm) { _driver = driver; _controlFormProgramm = controlFormProgramm; } public void Tags(string tag, int time_wait, int limit, string filters, CancellationToken cancelToken) { _driver.Navigate().GoToUrl("https://www.instagram.com/explore/tags/" + tag); _driver.FindElement(By.CssSelector("#react-root > section > main > article > div.EZdmt > div > div > div:nth-child(1) > div:nth-child(1)")).Click(); // открыть пост Самая первая запись в теге double dlimit = Convert.ToDouble(limit); for (int i = 1; i <= limit; i++) { if (Form1.stoped != 1) { try { if (GetIsCheckedSubscribe() == false && Filters_word(filters) == true) { double di = Convert.ToDouble(i); _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.zZYga > div > article > header > div.o-MQd > div.PQo_0 > div.bY2yH > button")).Click(); //кнопка подпис. в открытом посте ControlFormProgramm.MsgLogBox.AddMsg(_driver.Url + " подписались" + " (" + filter_view_in_msg_box + ")"); _controlFormProgramm.ProcessBarSetValue(Convert.ToInt32(di / dlimit * 100)); _controlFormProgramm.SetTextStateLabel(limit + " / " + i + " (" + Convert.ToInt32(di / dlimit * 100) + " %)"); _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.EfHg9 > div > div > a.HBoOv.coreSpriteRightPaginationArrow")).Click(); //следующий пост cancelToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(time_wait)); } else { cancelToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(1)); ControlFormProgramm.MsgLogBox.AddMsg(_driver.Url + " пропускаем, уже подписаны или фильтр"); _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.EfHg9 > div > div > a.HBoOv.coreSpriteRightPaginationArrow")).Click(); //следующий пост i = i - 1; double di = Convert.ToDouble(i); _controlFormProgramm.SetTextStateLabel(limit + " / " + i + " (" + Convert.ToInt32(di / dlimit * 100) + " %)"); } if (i >= limit) { //цикл выполнен _controlFormProgramm.ProcessBarSetValue(100); ControlFormProgramm.MsgLogBox.AddMsg("======================="); ControlFormProgramm.MsgLogBox.AddMsg(" Завершено."); ControlFormProgramm.MsgLogBox.AddMsg("======================="); _controlFormProgramm.SetTextStateLabel("Завершено."); _controlFormProgramm.Stop(); } } catch (Exception e) { ControlFormProgramm.MsgLogBox.AddMsg("Error: " + e.Message); i = i - 1; _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.EfHg9 > div > div > a.HBoOv.coreSpriteRightPaginationArrow")).Click(); //следующий пост } } //принудительная остановка else { i = limit; _controlFormProgramm.ProcessBarSetValue(100); ControlFormProgramm.MsgLogBox.AddMsg("======================="); ControlFormProgramm.MsgLogBox.AddMsg(" Остановлено."); ControlFormProgramm.MsgLogBox.AddMsg("======================="); _controlFormProgramm.SetTextStateLabel("Остановлено."); _controlFormProgramm.Stop(); } } } public void Geolocation(string geonumber, int time_wait, int limit, string filters, CancellationToken cancelToken) { _driver.Navigate().GoToUrl("https://www.instagram.com/explore/locations/" + geonumber); _driver.FindElement(By.CssSelector("#react-root > section > main > article > div.EZdmt > div > div > div:nth-child(1) > div:nth-child(1)")).Click(); // открыть пост Самая первая запись в теге double dlimit = Convert.ToDouble(limit); for (int i = 1; i <= limit; i++) { if (Form1.stoped != 1) { try { if (GetIsCheckedSubscribe() == false && Filters_word(filters) == true) { double di = Convert.ToDouble(i); _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.zZYga > div > article > header > div.o-MQd > div.PQo_0 > div.bY2yH > button")).Click(); //кнопка подпис. в открытом посте ControlFormProgramm.MsgLogBox.AddMsg(_driver.Url + " подписались" + " (" + filter_view_in_msg_box + ")"); _controlFormProgramm.ProcessBarSetValue(Convert.ToInt32(di / dlimit * 100)); _controlFormProgramm.SetTextStateLabel(limit + " / " + i + " (" + Convert.ToInt32(di / dlimit * 100) + " %)"); _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.EfHg9 > div > div > a.HBoOv.coreSpriteRightPaginationArrow")).Click(); //следующий пост cancelToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(time_wait)); } else { cancelToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(1)); ControlFormProgramm.MsgLogBox.AddMsg(_driver.Url + " пропускаем, уже подписаны или фильтр"); _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.EfHg9 > div > div > a.HBoOv.coreSpriteRightPaginationArrow")).Click(); //следующий пост i = i - 1; double di = Convert.ToDouble(i); _controlFormProgramm.SetTextStateLabel(limit + " / " + i + " (" + Convert.ToInt32(di / dlimit * 100) + " %)"); } if (i >= limit) { //цикл выполнен _controlFormProgramm.ProcessBarSetValue(100); ControlFormProgramm.MsgLogBox.AddMsg("======================="); ControlFormProgramm.MsgLogBox.AddMsg(" Завершено."); ControlFormProgramm.MsgLogBox.AddMsg("======================="); _controlFormProgramm.SetTextStateLabel("Завершено."); _controlFormProgramm.Stop(); } } catch (Exception e) { ControlFormProgramm.MsgLogBox.AddMsg("Error: " + e.Message); i = i - 1; _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.EfHg9 > div > div > a.HBoOv.coreSpriteRightPaginationArrow")).Click(); //следующий пост } } //принудительная остановка else { i = limit; _controlFormProgramm.ProcessBarSetValue(100); ControlFormProgramm.MsgLogBox.AddMsg("======================="); ControlFormProgramm.MsgLogBox.AddMsg(" Остановлено."); ControlFormProgramm.MsgLogBox.AddMsg("======================="); _controlFormProgramm.SetTextStateLabel("Остановлено."); _controlFormProgramm.Stop(); } } } public Boolean GetIsCheckedSubscribe() { String getAttribut; Boolean ischeck; getAttribut = _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.zZYga > div > article > header > div.o-MQd > div.PQo_0 > div.bY2yH > button")).GetAttribute("class"); Console.WriteLine(getAttribut); if (getAttribut == "oW_lN _0mzm- sqdOP yWX7d _8A5w5 ") { ischeck = true; } else { ischeck = false; } return ischeck; } public Boolean Filters_word(string _filter_words) { bool result; String bodyText=" "; if (Form1.MyGlavForm.checkBox1.Checked == true) { String filters = _filter_words; try { IWebElement body = _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.zZYga > div > article > div.eo2As > div.EtaWk")); bodyText = body.Text; //текст поста #react-root > section > main > div > div > article > div.eo2As > div.KlCQn.EtaWk > ul > li > div > div > div > span } catch (Exception ) { filter_view_in_msg_box = "null"; return result = true; } // Console.WriteLine(bodyText); string[] words = filters.Split(','); foreach (string word in words) { result = Regex.IsMatch(bodyText, @"\b" + word + @"\b", RegexOptions.IgnoreCase); if (result == true) { filter_view_in_msg_box = word; return result; } } return result = false; } else { return result = true; } } } Класс лайкер class Like { String filter_view_in_msg_box = "без фильтров"; private IWebDriver _driver; private ControlFormProgramm _controlFormProgramm; public Like(IWebDriver driver, ControlFormProgramm controlFormProgramm) { _driver = driver; _controlFormProgramm = controlFormProgramm; } public void Tags(string tag, int time_wait, int limit, string filters, CancellationToken cancelToken) { _driver.Navigate().GoToUrl("https://www.instagram.com/explore/tags/"+tag); _driver.FindElement(By.CssSelector("#react-root > section > main > article > div.EZdmt > div > div > div:nth-child(1) > div:nth-child(1)")).Click(); // открыть пост Самая первая запись в теге double dlimit = Convert.ToDouble(limit); for (int i = 1; i <= limit; i++) { if (Form1.stoped != 1) { try { if (GetIsCheckedLike() == false && Filters_word(filters)==true) { double di = Convert.ToDouble(i); _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.zZYga > div > article > div.eo2As > section.ltpMr.Slqrh > span.fr66n > button")).Click(); //кнопка лайка в открытом посте ControlFormProgramm.MsgLogBox.AddMsg(_driver.Url + " лайк добавлен" +" ("+filter_view_in_msg_box+")"); _controlFormProgramm.ProcessBarSetValue(Convert.ToInt32(di / dlimit * 100)); _controlFormProgramm.SetTextStateLabel(limit + " / " + i + " (" + Convert.ToInt32(di / dlimit * 100) + " %)"); _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.EfHg9 > div > div > a.HBoOv.coreSpriteRightPaginationArrow")).Click(); //следующий пост cancelToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(time_wait)); } else { cancelToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(1)); ControlFormProgramm.MsgLogBox.AddMsg(_driver.Url + " пропускаем, уже лайкали или фильтр"); _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.EfHg9 > div > div > a.HBoOv.coreSpriteRightPaginationArrow")).Click(); //следующий пост i = i - 1; double di = Convert.ToDouble(i); _controlFormProgramm.SetTextStateLabel(limit + " / " + i + " (" + Convert.ToInt32(di / dlimit * 100) + " %)"); } if (i >= limit) { //цикл выполнен _controlFormProgramm.ProcessBarSetValue(100); ControlFormProgramm.MsgLogBox.AddMsg("======================="); ControlFormProgramm.MsgLogBox.AddMsg(" Завершено."); ControlFormProgramm.MsgLogBox.AddMsg("======================="); _controlFormProgramm.SetTextStateLabel("Завершено."); _controlFormProgramm.Stop(); } } catch (Exception e) { ControlFormProgramm.MsgLogBox.AddMsg("Error: " + e.Message); i = i - 1; _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.EfHg9 > div > div > a.HBoOv.coreSpriteRightPaginationArrow")).Click(); //следующий пост } } //принудительная остановка else { i = limit; _controlFormProgramm.ProcessBarSetValue(100); ControlFormProgramm.MsgLogBox.AddMsg("======================="); ControlFormProgramm.MsgLogBox.AddMsg(" Остановлено."); ControlFormProgramm.MsgLogBox.AddMsg("======================="); _controlFormProgramm.SetTextStateLabel("Остановлено."); _controlFormProgramm.Stop(); } } } public void Geolocation(string geonumber, int time_wait, int limit, string filters, CancellationToken cancelToken) { _driver.Navigate().GoToUrl("https://www.instagram.com/explore/locations/" + geonumber); _driver.FindElement(By.CssSelector("#react-root > section > main > article > div.EZdmt > div > div > div:nth-child(1) > div:nth-child(1)")).Click(); // открыть пост Самая первая запись в теге double dlimit = Convert.ToDouble(limit); for (int i = 1; i <= limit; i++) { if (Form1.stoped != 1) { try { if (GetIsCheckedLike() == false && Filters_word(filters) == true) { double di = Convert.ToDouble(i); _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.zZYga > div > article > div.eo2As > section.ltpMr.Slqrh > span.fr66n > button")).Click(); //кнопка лайка в открытом посте ControlFormProgramm.MsgLogBox.AddMsg(_driver.Url + " лайк добавлен" + " (" + filter_view_in_msg_box + ")"); _controlFormProgramm.ProcessBarSetValue(Convert.ToInt32(di / dlimit * 100)); _controlFormProgramm.SetTextStateLabel(limit + " / " + i + " (" + Convert.ToInt32(di / dlimit * 100) + " %)"); _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.EfHg9 > div > div > a.HBoOv.coreSpriteRightPaginationArrow")).Click(); //следующий пост cancelToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(time_wait)); } else { cancelToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(1)); ControlFormProgramm.MsgLogBox.AddMsg(_driver.Url + " пропускаем, уже лайкали или фильтр"); _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.EfHg9 > div > div > a.HBoOv.coreSpriteRightPaginationArrow")).Click(); //следующий пост i = i - 1; double di = Convert.ToDouble(i); _controlFormProgramm.SetTextStateLabel(limit + " / " + i + " (" + Convert.ToInt32(di / dlimit * 100) + " %)"); } if (i >= limit) { //цикл выполнен _controlFormProgramm.ProcessBarSetValue(100); ControlFormProgramm.MsgLogBox.AddMsg("======================="); ControlFormProgramm.MsgLogBox.AddMsg(" Завершено."); ControlFormProgramm.MsgLogBox.AddMsg("======================="); _controlFormProgramm.SetTextStateLabel("Завершено."); _controlFormProgramm.Stop(); } } catch (Exception e) { ControlFormProgramm.MsgLogBox.AddMsg("Error: " + e.Message); i = i - 1; _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.EfHg9 > div > div > a.HBoOv.coreSpriteRightPaginationArrow")).Click(); //следующий пост } } //принудительная остановка else { i = limit; _controlFormProgramm.ProcessBarSetValue(100); ControlFormProgramm.MsgLogBox.AddMsg("======================="); ControlFormProgramm.MsgLogBox.AddMsg(" Остановлено."); ControlFormProgramm.MsgLogBox.AddMsg("======================="); _controlFormProgramm.SetTextStateLabel("Остановлено."); _controlFormProgramm.Stop(); } } } public Boolean GetIsCheckedLike() { String getAttribut; Boolean ischeck; getAttribut = _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.zZYga > div > article > div.eo2As > section.ltpMr.Slqrh > span.fr66n > button > span")).GetAttribute("class"); Console.WriteLine(getAttribut); if (getAttribut == "glyphsSpriteHeart__outline__24__grey_9 u-__7") { ischeck = false; } else { ischeck = true; } return ischeck; } public Boolean Filters_word(string _filter_words) { bool result; String bodyText = " "; if (Form1.MyGlavForm.checkBox1.Checked == true) { String filters = _filter_words; try { IWebElement body = _driver.FindElement(By.CssSelector("body > div._2dDPU.vCf6V > div.zZYga > div > article > div.eo2As > div.EtaWk")); bodyText = body.Text; //текст поста #react-root > section > main > div > div > article > div.eo2As > div.KlCQn.EtaWk > ul > li > div > div > div > span } catch (Exception) { filter_view_in_msg_box = "null"; return result = true; } // Console.WriteLine(bodyText); string[] words = filters.Split(','); foreach (string word in words) { result = Regex.IsMatch(bodyText, @"\b" + word + @"\b", RegexOptions.IgnoreCase); if (result == true) { filter_view_in_msg_box = word; return result; } } return result = false; } else { return result = true; } } } Т.е. получается разница только в CSS селекторах, а код идентичный. Я сделал статический класс с константами public static class ConstantsApp { public const String app_version = "1.2"; public const String app_author = "Martinov A."; public const String url_tags = "https://www.instagram.com/explore/tags/"; // public const String url_geolocation = "https://www.instagram.com/explore/locations/"; // public const String html_mark_open_first_post = "#react-root > section > main > article > div.EZdmt > div > div > div:nth-child(1) > div:nth-child(1)"; // открыть пост Самая первая запись в теге public const String html_mark_panel_textbox = "body > div._2dDPU.vCf6V > div.zZYga > div > article > div.eo2As > div.EtaWk"; // панель, где находится текст поста public const String html_mark_button_next = "body > div._2dDPU.vCf6V > div.EfHg9 > div > div > a.HBoOv.coreSpriteRightPaginationArrow"; // кнопка следующий пост (так же, можно использовать событие клавы) public const String html_mark_button_like = "body > div._2dDPU.vCf6V > div.zZYga > div > article > div.eo2As > section.ltpMr.Slqrh > span.fr66n > button"; //кнопка лайка в открытом посте public const String html_mark_get_check_like = "body > div._2dDPU.vCf6V > div.zZYga > div > article > div.eo2As > section.ltpMr.Slqrh > span.fr66n > button > span"; // проверка стоит ли лайк public const String html_mark_button_subscribe = "body > div._2dDPU.vCf6V > div.zZYga > div > article > header > div.o-MQd > div.PQo_0 > div.bY2yH > button"; // //кнопка подпис. в открытом посте public const String html_mark_get_check_subscribe = "body > div._2dDPU.vCf6V > div.zZYga > div > article > header > div.o-MQd > div.PQo_0 > div.bY2yH > button"; // проверка, подписаны ли public const String html_mark_name_attribut_grey_like = "glyphsSpriteHeart__outline__24__grey_9 u-__7"; // имя атрибута когда лайк не стоит (серое сердечко) public const String html_mark_name_attribut_active_sucbscribe = "oW_lN _0mzm- sqdOP yWX7d _8A5w5 "; // имя атрибута когда не подписаны } И хочу что бы у меня был только один метод, а не 4. Буду просто селекторы разные передавать в метод из статического класса с константами. Но при этом хотелось бы, что бы было два класса. Другими словами два класса и только один общий метод у них ну или что-то вроде этого)) P.S. за код не ругайте, я только учусь. =)
Ответы
Ответ 1
я с АПИ твиттера не работал, потому покажу не боевой код, а скорее небольшое упражнение в ООП. Первым делом нам нужен класс твита. Поля твита я взял из головы, но сделал его неизменяемым классом, так как, насколько я помню, твит поменять нельзя public class TweetItem { public string Id { get; } public string Text { get; } public string Author { get; } public TweetItem(string id, string text, string author) { this.Id = id; this.Text = text; this.Author = author; } } Дальше, нам нужна возможность искать твиты. Так как поиск твитов может быть по разным критериям, я решил выделить интерфейс для поиска public interface ITweetFilter { IEnumerableGetTweets(); } Далее, какая-то реализация классов поиска public class TweetFilterByTag : ITweetFilter { private string _tag; public TweetFilterByTag(string tag) { _tag = tag; } public IEnumerable GetTweets() { throw new NotImplementedException(); } } public class TweetFilterByGeo : ITweetFilter { private string _geo; public TweetFilterByGeo(string geo) { _geo = geo; } public IEnumerable GetTweets() { throw new NotImplementedException(); } } Поскольку поиск можно комбинировать, я решил также накатать композитный поиск. public class TweetFilterComposite : ITweetFilter { private ITweetFilter[] _filters; public TweetFilterComposite(params ITweetFilter[] filters) { _filters = filters; } public IEnumerable GetTweets() { var foundTweets = new HashSet (); foreach (var filter in _filters) foreach (var tweet in filter.GetTweets()) if (foundTweets.Add(tweet.Id)) yield return tweet; } } Далее, нам нужны классы, один для постановки лайков, второй - для подписки. public class TweetLiker { public void SetLike(TweetItem tweet) { throw new NotImplementedException(); } } public class TweetSubscriber { public void Subscribe(TweetItem tweet) { throw new NotImplementedException(); } } Осталось соединить всё вместе в нашей логике public class MyLogic { private TweetLiker _liker; private TweetSubscriber _subscriber; public MyLogic(TweetLiker liker, TweetSubscriber subscriber) { _liker = liker; _subscriber = subscriber; } public void SetLike(ITweetFilter filter) { foreach(var tweet in filter.GetTweets() _liker.SetLike(tweet); } public void Subscribe(ITweetFilter filter) { foreach (var tweet in filter.GetTweets() _subscriber.Subscribe(tweet); } } Как всем этим пользоваться: создаем нужные фильтры, создаем логику и вперед. var filterByTag = new TweetFilterByTag("MyTag"); var filterByGeo = new TweetFilterByGeo("MyCity"); var compositeFilter = new TweetFilterComposite(filterByTag, filterByGeo); var myLogic = new MyLogic(new TweetLiker(), new TweetSubscriber()); myLogic.SetLike(compositeFilter); myLogic.Subscribe(compositeFilter);
Комментариев нет:
Отправить комментарий