Софтуерно Инженерство
Loading...
+ Нов въпрос
antonio_rtodorov avatar antonio_rtodorov 74 Точки

Смисъла от употреба на "Private"?

Здравейте,

имам модификатор за достъп "Private", той се използва за да се капсулират данни, които не искаме да се достъпват от другите класове или създаваме get..(), който позволява да използването на private елемнтите в друг клас, който искам да ги виждам.

Примерите са ми следните, имам 20 класа правя си в един клас private Sting name; искам 18 класа с помоща на get..() да достъпят name, a eдин да клас да не може да го достъпи. Идва другия момент правя си public String name; в един клас и така той става достъпен за всичките 19 класа, обаче пиша съответния name като код в 18 класа, като в 19тия клас изобщо не го пиша като код. Въпроса ми е, защо тогава се счита, че като използваш  "Private" си защитаваш кода, като в двата случая, чрез код определяш кой клас да го достъпва?

 

Може да разледате и този пример http://www.progressivejava.net/2012/12/set-and-get-what-they-are-and-how-to-use-these-methods-correctly.html в който пак не ми става ясно защо трите елемента са private и ги достъпвам с get за да ги намнипулирам, защо просто не ги направя public пък аз ще определям кой клас да ги ползва.

Много ще съм ви благодарен за обяснение и примери!

Поздрави

Тагове:
0
C# OOP Basics 28/03/2016 13:18:25
g.stoyanov avatar g.stoyanov 776 Точки

Смисъла на get() е в това че можеш да манипулираш данните за външния свят.

Например:

имаме клас Кола

който има прайвът поле Километри

вътрешно класа може да работи с реалните километри но в гетъра да сложим

return kilometers - 20000;

 

Може би не е много добър примера но дано си схванал идеята.

 

Целта на сетера пък е да правим някакви операции върху входните данни - например валидация.

 

Иначе може да се направи един базов клас със прайвът поле, който да се наследява и отделно да направим интерфейс който да задължава публичността на това поле чрез гетер и евентуално сетер.

След това спокойно може да си направим колекция от различни класове(наследници на базовия) които имплементират този интерфейс и така  да работим върху публичното поле.

Ако не ти е станало още ясно, кажи за някакви по-детайлни обяснения с примери.

 

П.С.: Абсолютно си прав, че ако не използваш някаква къстъм логика върху полето, и ти трябва във всички класове може да го сложиш в един базов клас с гетер и сетер и да наследяваш класа - това се счита за добра практика. Не се препоръчва да се използват директно публични променливи в класа.

1
28/03/2016 13:40:12
antonio_rtodorov avatar antonio_rtodorov 74 Точки

Първо искам много да ти благодаря за отзивчивостта! :) Но не съм си го изяснил достатъчно. Ще използвам твоя пример с малка промяна

имаме клас Кола

който има прайвът поле Стойност

вътрешно класа може да работи с реалните километри но в гетъра да сложим

return Стойност - 20 000;

Имам Клас Мерцедес

чрез гетСтойност() достъпвам сумата и я манипулирам по някакъв начин и я правя 10 000; в друг случай правя стойност да е публик и така без да е нужно да използвам гет пак мога да я маниплира.

Тука идва недоброжелателен човек и ми разбива системата с цел да промени стойността от 10 000лв на 2 000лв. , обаче и двата случая даден клас наследник може да използва данните и да се манипулира стойността. Идеята за private не е ли точно тази да блокира именно този тип промяна от хакери, въпроса е, че или не мога да си го представя като хората или private защита няма нищо общо с хакерите?

0
g.stoyanov avatar g.stoyanov 776 Точки

Значи няма как хакер да влезе и да разбие класа :).

Просто с гетера и сетера контролираш как да се използва ресурса - този ресурс който трябва да е публичен, под публичен разбирай че може да го използват всички. Иначе останалите ресурси са прайвът и никой няма достъп до тях.

 

Ако искаш вече различните класове които наследяват базовия клас да имат различни поведения на контрола на публичните полета - може да го направиш като интерфейс както написах преди малко. Ако не ти е ясно за какво говоря - пиши ще ти обясня по-подробно.

 

П.С.: Ако искаш дай един по-конкретен случай който те мъчи, за да се опитаме да ти покажем как се прави.

0
28/03/2016 14:11:36
Filkolev avatar Filkolev 4501 Точки

Класическа грешка е да се бърка капсулацията със сигурност. Идеята на капсулацията е да се скрие имплементацията и да се покаже само каквото е нужно. Така по подразбиране всичко е скрито и ако трябва да бъде показано на външния свят, когато говорим за данни, демек полета, се правят публични гетъри и сетъри. Това не те защитава от хакери, но подсигурява, че при липса на умисъл приложението да бъде счупено, въпросният клас ще се ползва по правилен и улеснен начин.

2
netherblood avatar netherblood 94 Точки

Въпрос на удобство е при по-сложен код.

Представи си имаш написани getter и setter на някой елемент в твоя програма. Минават три месеца, забравил си за нея, но решаваш че искаш да сложиш проверка дали елемента не е null. Слагаш проверка в твоя setXXX метод и си готов.

Сега, ако нямаше тези get и set написани, трябва общо взето да преминеш целия код (който може да не е 2 класа, а 100) и да направиш проверка. Отгоре на всичко, тази проверка трябва да я пишеш всеки път когато въвеждаш нов код.

Има и други ползи като по-лесно дебъгване и предполагам куп други неща. Тези практики са влезли чрез години опит и главоболия от програмисти преди нас, не се съмнявай в тях твърде много, хаха.

0
28/03/2016 15:14:07
Filkolev avatar Filkolev 4501 Точки

Нещо, което май не е споменато, но е доста важно - при добра абстракция публичните полета не вършат работа. Под добра абстракция имам предвид наличието на подходящи интерфейси и класова йерархия. 

Всичко, което трябва да може да се достъпва извън класа, трябва да е част от интерфейс, а в интерфейс не може да се слагат данни (полета), а само методи (вкл. пропъртита, индексатори и ивенти).

Да кажем, че си направил подобно приложение и имаш нещо подобно (най-базов скелет):

public interface IVehicle
{
    public int Kilometers { get; }    
}
public class Car : IVehicle
{
    public string model;

    private int kilometers;

    // constructor

    public int Kilometers => this.kilometers;
}

Ако работиш правилно, в приложението си би трябвало да ползваш IVehicle, което значи, че ще имаш достъп до километрите, но не и до модела на автомобила. За да може да го достъпиш, трябва да кастваш, което е много грозно и не много правилно:

IVehicle car = new Car();
string model = ((Car)car).model;

Ползвайки публични полета, а не гетъри, дефинирани в интерфейси, приложението ти ще е осакатено.

Затова, дори когато не правиш никакви валидации или обработки, правилният подход е да направиш автоматични пропъртита, а не публични полета.

 

1
g.stoyanov avatar g.stoyanov 776 Точки

Напълно те подкрепям колега,

това и аз се опитах да кажа. Примера е отличен, ако колегата има някакъв по-конкретен пример си мисля, че бихме му помогнали повече.

0