Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.62/13: Рейтинг темы: голосов - 13, средняя оценка - 4.62
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146

Какой это шаблон проектирования, и можно ли сделать в C# также (как в С++)?

08.11.2017, 00:33. Показов 2628. Ответов 21
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день.

Когда я сталкивался ранее с наследованием классов и полиморфизмом, то это было или,

1) дописывание каких то новых методов в класс-потомок, которых не было в классе-предка. (обычное наследование).
2) переопределение некоторых методов, объявленных в базовом классе как virtual, (обычный полиморфизм), причем сигнатурна методов оставалась одинаковой.

А можно ли унаследовать сразу множество связанных классов? Т.е. как бы целый проект из связных классов, унаследуется от базового проекта, тех же классов, каждый в своем множестве унаследован от класса-прототипа в базовом проекте?
упростим задачу до предела — множество из 2-х классов, должно унаследоваться от другого множества из 2-х классов.
Допустим, это будут классы SpecialEntity унаследованный от ModuleEntity (1-й уровень), и
SpecialAlgorithmic от ModuleAlgorithmic, (2-й уровень).

Получается, чтобы так сделать, нам нужно унаследовать некий класс SpecialAlgorithmic от ModuleAlgorithmic, да так,
чтобы 1) его поля объявленные как ModuleEntity entity;
просто стали полями унаследуемого типа, SpecialEntity entity;
2) Методы, к примеру, назовем, AlgorithmOfModule — нужно переопределить (override), да так, что
его сигнатура "почти такая же", но не совсем — этот метод должен уже принимать унаследуемые ссылки на
SpecialEntity вместо ModuleEntity.
Т.е. на псевдо-языке, получится что то типа такого --

Code
1
2
3
4
5
6
7
8
9
public class SpecialAlgorithmic : ModuleAlgorithmic // некая сущность в базовом проекте Module
{
public SpecialEntity entity : override ModuleEntity entity; // override field from ModuleAlgorithmic class — field entity
 
public override SpecialEntity[] AlgorithmOfModule(SpecialEntity param) : ModuleEntity[] AlgorithmOfModule(ModuleEntity param)
{
// ...
}
}

Тогда получается, в вызывающем коде, работа с производным проектом, будет практически такой же,
как и работа с базовым проектом (нужно будет только заменить 'Module' на 'Special'), что
значительно упрощает разработку проектов, которые будут развиваться из некоего шаблонного проекта.

Долго думая, на C++ мне удалось реализовать данный шаблон проектирования.
Получилось так -


C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//-------------ModulePosition  + SpecialPosition--------------------------------------------
 
 
 
 
struct ModulePosition
{
    __int64 data0;
};
 
 
 
struct SpecialPosition : ModulePosition
{
public:
    __int64 data2;
};
 
 
       //  объявлены как структуры, но сути шаблона проектирования это не меняет, аналогично было бы и с class
 
 
//------------------ModuleDrive + SpecialDrive--------------------------------------------
 
 
template< class Type >
class TemplateDrive
{   
public:
    Type field;
    Type MethodGet(Type element);
};
 
 
typedef TemplateDrive<ModulePosition> ModuleDrive;
 
 
 
// далее использование  ModuleDrive - ЭКВИВАЛЕНТНО TemplateDrive<ModulePosition>,  
// а потому класс, использующий именно ModulePosition, мы можем дописать как  ModuleDrive. 
// Попытка использовать с другим типом  TemplateDrive<ДругойТип>  провалится потому что в шаблонном class TemplateDrive - 
// нет реализации метода для всех других типов. По сути, конструкция выше эквивалентна конструкции C# 
// public partial class TemplateDrive<T> where T : ModulePosition
// и даже лучше т.к. в C# нельзя использовать везде без ограничений using ModuleDrive = TemplateDrive<ModulePosition>;  
// так, как в C++  typedef.  (using для этих целей можно использовать только в начале namespace).  
// Необъявление же реализации метода MethodGet - в классе TemplateDrive - так же решается и в C#, только с объявлением  abstract. 
// Поля в ModuleDrive объявляются закомментированными для удобства так же как и в C++, остаётся несущественная разница - 
// т.к. в C++ нет partial слова, то приходится комментировать и сам класс ModuleDrive, оставляя только реализацию методов. 
 
 
 
//class ModuleDrive   //  фактически - реализация класса будет здесь, но из-за отсутствия 'partial' приходится часть - оставлять в одном месте. 
//{
//public:
    //ModulePosition field;    //  Type field;  превращается в ModulePosition, т.к. в typedef объявлен тип 
 
 
    // здесь слово virtual повторно не нужно, т.к.  метод определен внутри класса TemplateDrive, видимо модификаторы virtual можно об-ть только внутри класса.
    // Если этот метод объявить как virtual в классе TemplateDrive тогда придется полностью переписывать код, а так - 
    // можно что то дописать в производных классах,  а часть оставить здесь и попадать сюда, в код базового класса тоже. 
    ModulePosition ModuleDrive::MethodGet(ModulePosition element)      // сигнатура та же, но Type -> превращается в ModulePosition
    {
        element.data0 = 11;   // "Точка1"
        field.data0 = 11;
        return element;
    }
//}    //  class ModuleDrive  
 
 
 
 
// Linker error LNK1120: 1 unresolved externals 
// TemplateDrive<SpecialPosition>* td2 = new TemplateDrive<SpecialPosition>();
// чтобы не было этой ошибки, нужно определить и в этом классе MethodGet, точнее - вызвать базовый 
    SpecialPosition TemplateDrive<SpecialPosition>::MethodGet(SpecialPosition element)      // сигнатура та же, но Type -> превращается в ModulePosition
    {
        //element.data0 = 11;
        //field.data0 = 11;
        //return element;
 
        ModulePosition el =  ((ModuleDrive*)this)->MethodGet((ModulePosition)element);  // "Точка2"
        element.data0 = el.data0;
        return element;
    }
 
 
 
// класс SpecialDrive, в отличие от ModuleDrive уже не объявляется через typedef, а прямо наследуется от TemplateDrive<SpecialPosition>. 
// Поскольку ModuleDrive  в свою очередь, не наследовался в другую ветку, а объявлялся прямо, то 
// 1) TemplateDrive<SpecialPosition>  ------> объект  наследник    от  ModuleDrive  (эквивалентен ему и  TemplateDrive<ModulePosition>)
//     поскольку тип в шаблоне - наследник. (SpecialPosition).  См.. свойство КОВАРИАНТНОСТИ. 
//     Содержит новое только в SpecialPosition внутреннем типе 
// 2) SpecialDrive - наследник от  TemplateDrive<SpecialPosition>, и следовательно от ModuleDrive. (содержит что то свое новое)
//     это значит что если сравнить SpecialDrive и ModuleDrive - то внутри и тип полей которые были ModulePosition- заменится на производные, 
//     и сигнатуры методов использующие этот тип,   и к тому же, сами методы можно переопределить,  + создать новые. 
// МНОГОКЛАССОВОЕ наследование в этом и состоит. - 
//  Ниже, попадем в  "Точка3"   "Точка2"    "Точка1"  - последовательно, используя SpecialDrive  объект 
 
 
class SpecialDrive : TemplateDrive<SpecialPosition>
{
public:
    //SpecialPosition field;    //  Type field;  здесь превращается в SpecialPosition, т.к. тип объявлен у класса предка 
    int field2;   //  новое поле 
 
 
    // сигнатура та же, но Type -> превращается в SpecialPosition  - компилятор не ругается! 
    SpecialPosition MethodGet(SpecialPosition element) 
    {
        
        //element = TemplateDrive<SpecialPosition>::MethodGet(element); 
        element = ((TemplateDrive<SpecialPosition>*)this)->MethodGet(element);  // "Точка3"
 
        // доопределяем своё
        element.data2 = 22;
        field.data0 = 22;
 
        return element;
    }
};
 
 
 
void CFreecellTemplateCppDlg::OnBnClickedOk()
{
    
    ModuleDrive md1;
    TemplateDrive<SpecialPosition> td1;
    SpecialDrive sd1;
 
    // выше видно, что от чего наследуется,  ModuleDrive   ->  TemplateDrive<SpecialPosition>   ->  SpecialDrive
    //Watch:
    //в md1 видим что поле field имеет тип  ModulePosition
    //в td1 видим что поле field имеет тип  SpecialPosition
    //в sd1 - еще появилось поле field2
 
 
 
 
    ModuleDrive* m1 = new ModuleDrive();
    SpecialDrive* m3 = new SpecialDrive();
 
    ModulePosition posM;
    posM.data0 = 100;
    m1->MethodGet(posM);   // 
 
    SpecialPosition posS;
    posS.data0 = 100;
    m3->MethodGet(posS);   //  Здесь, попадем в  "Точка3"   "Точка2"    "Точка1"  - последовательно, используя SpecialDrive  объект 
 
 
    // таким образом SpecialDrive НЕЯВНО унаследован от ModuleDrive,  одновременно с внутренними полями и сигнатурами методов, 
    // у SpecialDrive  внутри везде используется SpecialPosition,  а у ModuleDrive  - используется ModulePosition.  
 
    // Получается многоклассвое наследование.  Если далее создать еще пару классов,  к примеру 
    // ModuleController  и   SpecialController (3-й уровень),  второй так же неявно унаследовать от первого, а внутренние классы у них будут 
    // использоваться, вышеописанные  ModuleDrive и SpecialDrive (2-й уровень)  соответственно, то получим уже связное множество из 3-х классов, 
    // унаследованное от связного множества из  3-х классов. 
    // Продолжая по аналогии,  можно создать целый проект из N классов, который можно использовать как базовый для 
    // другого проекта, из унаследованных этих N классов. 
    
 
 
 
    CDialogEx::OnOK();
}
 
 
 
 
//----------------------------------------------------------------------------------------------------
Хочу спросить,
я изобретаю велосипед, или этот шаблон проектирования реально существует, и имеет какое то название?

И еще интересно - можно ли подобное реализовать на C# ?

Спасибо.
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
08.11.2017, 00:33
Ответы с готовыми решениями:

Шаблон проектирования Prototype. Можно ли по такой реализации сказать, что используется этот шаблон?
public interface ICloneable&lt;T&gt; { T Clone(); } public class Client : ICloneable&lt;Client&gt; { ...

Можно ли применить шаблон проектирования?
Есть 3 класса. Класс 2 создержит массив из объектов класса 1. Класс 3 содержит массив из объектов класса 2. Т.е. сплошная...

Можно ли в данном случае использовать шаблон проектирования Bridge
Здравствуйте! Допустим, есть модели абсолютно разной природы (например, пользователь и каптча), которые просто хранят данные. Они...

21
Эксперт .NET
 Аватар для Usaga
14139 / 9368 / 1350
Регистрация: 21.01.2016
Сообщений: 35,267
08.11.2017, 06:58
SergeyYN, довольно сложно распарсить эту портянку потока сознания.

В C# нет множественного наследования, у класса может быть только один класс-предок. Всё содержимое предка наследуется как есть (включая приватное барахло, к которому нет доступа) и класс-потомок воспринимается внешним кодом как базовый, если работа с ним идёт через ссылку на базовый тип.

Переопределять можно только методы с той же сигнатурой. Добавить аргументов переопределённому методу нельзя, это уже будет тупо другой метод (перегрузка).
0
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
08.11.2017, 08:03  [ТС]
довольно сложно распарсить

Хорошо - вот проще. Есть некий код, используется N классов. В примере ниже - только 2 класса.

C#
1
2
3
4
ModuleEntity param = new ModuleEntity( /* ... */ );
ModuleEntity modEnt = new ModuleEntity( /* параметры создающие объект */ );
ModuleAlgorithmic modAlg = new ModuleAlgorithmic(modEnt);
ModuleEntity[] result = modAlg.AlgorithmOfModule(param);
Нужно спроектировать 2 унаследованные класса ModuleEntity->SpecialEntity и ModuleAlgorithmic->SpecialAlgorithmic
так, чтобы в вызывающем коде, всё что нужно было сделать - это 'Module' на 'Special' везде - позаменять,
и должно работать. В частности, метод AlgorithmOfModule - будет иметь не совсем такую же сигнатуру,
а сигнатуру, в которой класс-предок заменен классом потомком. (и поля внутри класса аналогично).
Также, AlgorithmOfModule может быть как виртуальным (полностью переписанным в классе-потомке),
так и обычным методом, часть кода которого - можно вызвать из объекта предка.

SpecialEntity param = new SpecialEntity( /* ... */ );
SpecialEntity modEnt = new SpecialEntity( /* параметры создающие объект */ );
SpecialAlgorithmic modAlg = new SpecialAlgorithmic(modEnt);
SpecialEntity[] result = modAlg.AlgorithmOfModule(param);

Надеюсь, так понятнее.
Можно это сделать на C# ?
Ну вот, на C++ вышло, что это сделать можно.
(выше я подробно это и расписал),
И здесь не "множественное наследование". "Многоклассовое" - этот термин я сам придумал.
(точнее - наследование путем Ковариантности + обычное в генерик-классах).
Получается такой шаблон проектирования, в котором, N связных классов в одном проекте - наследуется
сразу N связными классами в другом проекте.
0
Эксперт .NET
 Аватар для Usaga
14139 / 9368 / 1350
Регистрация: 21.01.2016
Сообщений: 35,267
08.11.2017, 08:08
SergeyYN, ну, тут либо обобщённые базовые классы, либо SpecialAlgorithmic должен работать с SpecialEntity через его базовый класс ModuleEntity и тогда сигнатура метода и все поля класса не изменятся.
1
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
08.11.2017, 08:17  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
Добавить аргументов переопределённому методу нельзя, это уже будет тупо другой метод (перегрузка).
Аргументы не добавлялись.

Цитата Сообщение от Usaga Посмотреть сообщение
Переопределять можно только методы с той же сигнатурой.
А у меня получилось сигнатура "почти та же", т.е. замененная только на наследуемый тип - параметр метода,
и возвращаемый объект.
См. метод MethodGet - в объекте SpecialDrive, там же проваливаемся в "Точка3" "Точка2" "Точка1" .
А "Точка1" - часть кода выполнялось в методе MethodGet - объекта ModuleDrive.

сигнатура метода MethodGet в классе SpecialDrive вот такая -

SpecialPosition MethodGet(SpecialPosition element)

а сИгнатура метода MethodGet в классе ModuleDrive вот такая -

ModulePosition MethodGet(ModulePosition element)

тем не менее, метод MethodGet самый что ни есть "переопределенный", т.к. SpecialDrive унаследован от ModuleDrive.
Если его определить как virtual, то вызовется версия в зависимости от типа ранее созданного объекта.
0
Эксперт .NET
 Аватар для Usaga
14139 / 9368 / 1350
Регистрация: 21.01.2016
Сообщений: 35,267
08.11.2017, 08:22
Цитата Сообщение от SergeyYN Посмотреть сообщение
А у меня получилось сигнатура "почти та же", т.е. замененная только на наследуемый тип - параметр метода,
Потому, что вы использовали шаблон класса (обобщённый класс - в терминах C#), а не наследование. Немного разные вещи.
0
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
08.11.2017, 08:40  [ТС]
Цитата Сообщение от SergeyYN Посмотреть сообщение
Если его определить как virtual, то вызовется версия в зависимости от типа ранее созданного объекта.
Дополню, можно сделать так, что в коде
C++
1
2
3
4
5
6
7
8
    ModuleDrive* m1 = new ModuleDrive();
    ModuleDrive* m3 = (ModuleDrive*) new SpecialDrive();
 
    ModulePosition posM;
    posM.data0 = 100;
 
    m1->MethodGet(posM);   
    m3->MethodGet(posS);
вызовутся разные методы MethodGet, если их объявить как virtual. Получается, и метод переопределенный,
и сигнатура у него отличается.

Цитата Сообщение от Usaga Посмотреть сообщение
обобщённые базовые классы
А как называется подобный шаблон проектирования? Вот допустим, есть базовый проект, с 4 классами

ModuleEntity , ModuleAlgorithmic , ModulePosition , ModuleController.

Каждый следующий класс - использует предыдущий, т.е. ModuleAlgorithmic использует ModuleEntity , а не наоборот.
Пишем производный проект, у нас будут 4 унаследованных класса

SpecialEntity , SpecialAlgorithmic , SpecialPosition , SpecialController.

аналогично, каждый следующий класс - использует предыдущий, т.е. SpecialAlgorithmic использует SpecialEntity , а не наоборот.
Добиться на C++ как выше было видно, можно путем 1) создания классов-шаблонов, 2) правильного использования typedef,
3) правильного наследования от класса-шаблона.

Добавлено через 3 минуты
Цитата Сообщение от Usaga Посмотреть сообщение
Потому, что вы использовали шаблон класса (обобщённый класс - в терминах C#), а не наследование. Немного разные вещи.
Да, шаблон использовался.
Но наследование там тоже было - в моём примере -

ModuleDrive -> TemplateDrive<SpecialPosition> -> SpecialDrive

класс справа - унаследован от класса слева. Таким образом SpecialDrive неявно унаследован от ModuleDrive .
Через ковариантность, и только позже - через обычное наследование.

Если подобное реализовать на C#, то (SpecialDrive is ModuleDrive ) - должно выдать true.

В внутри они используют разные типы объектов, первый - SpecialPosition, а второй - ModulePosition.
В полях и сигнатурах своих методов.
0
Эксперт .NET
 Аватар для Usaga
14139 / 9368 / 1350
Регистрация: 21.01.2016
Сообщений: 35,267
08.11.2017, 17:20
Цитата Сообщение от SergeyYN Посмотреть сообщение
вызовутся разные методы MethodGet, если их объявить как virtual. Получается, и метод переопределенный,
и сигнатура у него отличается.
Да ладно)) Для вас это - новость?

А такое вас сильно удивит?
C++
1
ModuleDrive* m3 = new SpecialDrive();
Я так и не понял, в чём у вас проблема. Вы толи вообще слабо представляете что-такое наследование и как им пользоваться, толи хотите чего-то своеобразного...
0
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
08.11.2017, 19:07  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
Я так и не понял, в чём у вас проблема
1) какой это шаблон проектирования (как называется? чтобы почитать целую теорию о нем),
2) можно ли подобное сделать на C# то что описано в C++ коде ?


Цитата Сообщение от Usaga Посмотреть сообщение
толи хотите чего-то своеобразного...
Именно. Потому что,
То, что я описал - не видел чтобы кто то использовал в проектах. Даже название шаблона проектирования
не найти, с похожим описанием. Генерик классы + наследование + typedef, +
двухшаговое наследование - Ковариантность + обычное в генерик-классах.

Всё для того, чтобы в конечном итоге в вызывающем коде, можно было сразу целое множество классов
заменить, т.е. просто приставку 'Module' на 'Special' заменить, и тем самым получить,
схожий код при работе с разными проектами.
0
Эксперт .NET
 Аватар для Usaga
14139 / 9368 / 1350
Регистрация: 21.01.2016
Сообщений: 35,267
08.11.2017, 19:35
Цитата Сообщение от SergeyYN Посмотреть сообщение
какой это шаблон проектирования (как называется? чтобы почитать целую теорию о нем),
Наследование. И это не "шаблон проектировани".

Цитата Сообщение от SergeyYN Посмотреть сообщение
можно ли подобное сделать на C# то что описано в C++ коде ?
Да, просто наследуетесь.

Цитата Сообщение от SergeyYN Посмотреть сообщение
Всё для того, чтобы в конечном итоге в вызывающем коде, можно было сразу целое множество классов
заменить, т.е. просто приставку 'Module' на 'Special' заменить, и тем самым получить,
схожий код при работе с разными проектами.
Да, просто заменяете класс унаследованным от него.
0
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
08.11.2017, 19:44  [ТС]
Так тут не просто "заменяете класс унаследованным от него." Тут целый проект, из связных
N-классов унаследован от другого проекта с N класами.

Цитата Сообщение от SergeyYN Посмотреть сообщение
Получается, и метод переопределенный, и сигнатура у него отличается.
Цитата Сообщение от Usaga Посмотреть сообщение
Для вас это - новость?
вот к примеру, как переопределить virtual метод с другой сигнатурой да, не встречал ранее. Потому сам и придумываю
шаблон проектирования.


C++
1
2
3
virtual ModulePosition MethodGet(ModulePosition element) 
 
override SpecialPosition MethodGet(SpecialPosition element)
сигнатуры у них разные. Можно как то проще сделать, чтобы достаточно было везде по коду заменить приставку?
Т.е. автоматически меняются и сигнатуры методов внутри классов, и типы полей, и типы в коде!
Без generic + typedef в приведенном случае вроде, не обойтись.

Цитата Сообщение от Usaga Посмотреть сообщение
либо SpecialAlgorithmic должен работать с SpecialEntity через его базовый класс ModuleEntity и тогда сигнатура метода и все поля класса не изменятся.
Можно, но так неудобнее. Парадигма то в том и заключается - что разработав целый проект (Module) с N классами,
и имея код, его использующий,

Разрабатываем другой проект, тоже с N классами, (Special), и любые другие проекты.
ВЕСЬ КОД который использует N классов, будет точно таким же, за исключением замены приставки.
'Module' - на 'Special'.

Кроме удобства восприятия, есть и другие более интересные возможности. Например, имея код,
распарсить его, заменить приставку в словах в автогенераторе кода, и запустить для другого проекта.

И не надо вникать, где там нужно через базовый класс ModuleEntity обращаться, а где надо напрямую
использовать SpecialEntity, и т.п. нюансы.
Но главное - эстетическая красота подобного решения.
0
Эксперт .NET
 Аватар для Usaga
14139 / 9368 / 1350
Регистрация: 21.01.2016
Сообщений: 35,267
08.11.2017, 19:50
Цитата Сообщение от SergeyYN Посмотреть сообщение
вот к примеру, как переопределить virtual метод с другой сигнатурой да, не встречал ранее.
И не встретите. Я уже объяснял почему.

Цитата Сообщение от SergeyYN Посмотреть сообщение
сигнатуры у них разные. Можно как то проще сделать, чтобы достаточно было везде по коду заменить приставку?
И на это я уже отвечал: принимайте в методах объекты одного класса. Реально же передавать можете наследников. Код-потребитель об этом не узнает.

Цитата Сообщение от SergeyYN Посмотреть сообщение
Можно, но так неудобнее. Парадигма то в том и заключается - что разработав целый проект (Module) с N классами,
и имея код, его использующий,
Разрабатываем другой проект, тоже с N классами, (Special), и любые другие проекты.
ВЕСЬ КОД который использует N классов, будет точно таким же, за исключением замены приставки.
'Module' - на 'Special'.
Это всё реализуется простым наследованием. Без шаблонов и уличной магии.

Цитата Сообщение от SergeyYN Посмотреть сообщение
И не надо вникать, где там нужно через базовый класс ModuleEntity обращаться, а где надо напрямую
использовать SpecialEntity.
Конечно не надо. Везде работаете через базовый класс и бед не знаете.
0
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
08.11.2017, 20:19  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
И не встретите. Я уже объяснял почему.
В C++ коде, который приводил в 1-м посту, где задается MethodGet - приписать virtual ,
а в унаследуемом SpecialDrive - тоже, то всё отлично работает. Т.е. для объекта типа SpecialDrive -
вызовется свой метод, а для ModuleDrive - свой. Причем сигнатуры у них действительно разные.
Проверял под дебаггером.
Не знаю правда, прокатит ли что то подобное в C#.

Цитата Сообщение от Usaga Посмотреть сообщение
принимайте в методах объекты одного класса.
какого? Есть цепочка классов
ModuleClass1, используется в ModuleClass2, этот используется в ModuleClass3, а этот в ModuleClass4.

т.е.
ModuleClass1
ModuleClass2 (принимает ModuleClass1)
ModuleClass3 (принимает ModuleClass2)
ModuleClass4 (принимает ModuleClass3 ModuleClass2)

Наследую целый проект. 4 класса будут такими -

SpecialClass1, используется в SpecialClass2, этот используется в SpecialClass3, а этот в SpecialClass4.

в определении методов - писать везде Module вместо Special в сигнатурах ?

т.е. я хотел

SpecialClass1
SpecialClass2 (принимает и использует SpecialClass1)
SpecialClass3 (принимает и использует SpecialClass2)
SpecialClass4 (принимает и использует SpecialClass3 SpecialClass2)

а вы предлагаете,

SpecialClass1
SpecialClass2 (принимает и использует ModuleClass1)
SpecialClass3 (принимает и использует ModuleClass2)
SpecialClass4 (принимает и использует ModuleClass3 ModuleClass2)

а потом делать явное преобразование внутри?

При обращении к полям, в вызываемом коде - писать Special.. ?

Т.е. надо разбираться где использовать одно слово, а где другое слово.

По сути то, что я пишу, это лучше называть не наследование классов.
Это наследование целых проектов.

Какие возможности новые могут быть, если нам не надо вникать, а можно просто заменить во всём коде
слова.

Допустим, я разработал некий проект, который назвал "SpecialProject", с классами, которые касаются
проекта, все начинаются с Special... (SpecialDrive, SpecialController, SpecialAlgorithmic и т.д. )
и dll этого проекта отдал другому производителю.

Производитель, используя мой dll, написал некую другую программу (у него на выходе будет exe файл),
которая использует этот dll.

Затем я разработал допустим, другой проект, который назвал "OtherProject",
с классами, которые касаются
проекта, все начинаются с Other... (OtherDrive, OtherController, OtherAlgorithmic и т.д. )
они унаследованы от прототипов классов первого проекта.

Тогда я могу дать новую dll производителю, и не требовать его код (да он может и не хотеть его отдавать),
для того чтобы переделать, а сказать типа "замени в своем проекте все 'Special' на 'Other' " - и всё заработает.

Или и вовсе, дать ему программу, которая удаленно рефлектором вынимет его код,
автогенератором заменив 'Special' на 'Other' - на новый, автобилдом - сделает ребилд, и у него готовый проект,
который обращается к т.н. "унаследованному проекту". А может даже, и ребилд проекта не потребуется,
если в своей dll заменить старый SpecialProject на ModuleProject, а OtherProject на SpecialProject .

Ну, это только одна из возможностей, реально же, больше всего именно красота решения нравится.
0
burning1ife
 Аватар для kenny69
1466 / 1287 / 294
Регистрация: 21.09.2008
Сообщений: 3,438
Записей в блоге: 9
09.11.2017, 00:48
Лучший ответ Сообщение было отмечено SergeyYN как решение

Решение

Для всего этого и придумали интерфейсы и IoC (Dependency Injection)

Прочитайте про принципы SOLID.
Те, которые на мой взгляд не соблюдены в данной реализации:

1. Принцип открытости/закрытости (Open-closed) - программные сущности должны быть открыты для расширения, но закрыты для модификации.

2. Принцип подстановки Барбары Лисков (Liskov substitution)

Вы при изменении сигнатуры вы усиливаете предусловия.

3. Принцип инверсии зависимостей (Dependency Invertion)

Зависимости внутри системы строятся на основе абстракций. Модули верхнего уровня не зависят от модулей нижнего уровня. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций

У вас классы зависят от других классов, а не от абстракций.

Добавлено через 17 минут
Цитата Сообщение от SergeyYN Посмотреть сообщение
Затем я разработал допустим, другой проект, который назвал "OtherProject",
с классами, которые касаются
проекта, все начинаются с Other... (OtherDrive, OtherController, OtherAlgorithmic и т.д. )
они унаследованы от прототипов классов первого проекта.
Тогда я могу дать новую dll производителю, и не требовать его код (да он может и не хотеть его отдавать),
для того чтобы переделать, а сказать типа "замени в своем проекте все 'Special' на 'Other' " - и всё заработает.
Вы описываете модульные приложения, которые реализуются с помощью Reflection и принципов SOLID
Тот же MEF и ему подобные.

Добавлено через 10 минут
Мне кажется, что ваша задача может решаться также с помощью Generic interface
1
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
09.11.2017, 02:51  [ТС]
kenny69, большое спасибо!
Сразу несколько направлений (я про них раньше не читал, интересно будет изучить),
и намного понятнее, в какую сторону смотреть.

А то бывает иногда, приходится что то принципиально новое разработать, а глубокое проектирование
в самом начальном этапе - самое важное (т.е. позже переделывать - будет намного труднее).
0
Эксперт .NET
 Аватар для Usaga
14139 / 9368 / 1350
Регистрация: 21.01.2016
Сообщений: 35,267
09.11.2017, 06:37
Цитата Сообщение от SergeyYN Посмотреть сообщение
В C++ коде, который приводил в 1-м посту, где задается MethodGet - приписать virtual ,
а в унаследуемом SpecialDrive - тоже, то всё отлично работает. Т.е. для объекта типа SpecialDrive -
вызовется свой метод, а для ModuleDrive - свой. Причем сигнатуры у них действительно разные.
Проверял под дебаггером.
Не знаю правда, прокатит ли что то подобное в C#.
Это уже не переопределение, сколько можно повторять. Вы наследуюетесь от обобщённого класса.

Цитата Сообщение от SergeyYN Посмотреть сообщение
а потом делать явное преобразование внутри?
Зачем?

Вы принимаете в своих классам аргрументы оперделённого, базового класса и не должны знать, что там на самом деле.
Такой код получается расширяемым.

Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using System;
 
namespace NetExperiments
{
    class A
    {
        public virtual void Print(string s)
        {
            Console.WriteLine("A" + s);
        }
    }
 
    class B : A
    {
        public override void Print(string s)
        {
            Console.WriteLine("B" + s);
        }
    }
 
    class Original
    {
        public virtual void DoIt(A input)
        {
            input.Print("");
        }
    }
 
    class Extended : Original
    {
        public override void DoIt(A input)
        {
            input.Print("dasf asdf"); // <- другая логика обработки входных данных
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            Original original = new Original();
            Original extended = new Extended();
 
            A a = new A();
            B b = new B();
 
            // Original можно передавать "расширенный" класс, но
            // он об этом не узнает.
            original.DoIt(a);
            original.DoIt(b);
 
            extended.DoIt(a);
            extended.DoIt(b);
 
            Console.ReadKey();
        }
    }
}
0
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
09.11.2017, 16:28  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
Это уже не переопределение, сколько можно повторять. Вы наследуюетесь от обобщённого класса.
А что такое "переопределение" ? Разберем похожий, на ваш пример.
У вас два класса базовые, это ваш класс A (назовем его SpecialClass1), и ваш класс Original
(назовем его SpecialClass2). Пусть они заключены в проект с названием SpecialProject. Его допустим,
скомпилировали в dll.

SpecialProject.dll : код определяющий <связное множество SpecialClass1, SpecialClass2, Special... >

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class SpecialClass1
{
        public int field;
}
 
 
public class SpecialClass2
{
        public SpecialClass1 field;
 
        public virtual SpecialClass1 DoIt (SpecialClass1  input)  // виртуальный 
        {
            //.... 
        }
 
        public SpecialClass1   DoThat (SpecialClass1  input)  // невиртуальный
        {
            //.... 
        }
}

Затем был написан внешний код, его использующий (exe-файл), как видно из приведенного вами примера, вот такой
(с переменованием, классов + добавил своё) -

Код для exe -- код использующий <связное множество SpecialClass1, SpecialClass2, Special... >

C#
1
2
3
4
5
6
SpecialClass1 a = new SpecialClass1();
SpecialClass2 myObj = new SpecialClass2();
myObj.field = a;
 
SpecialClass1 b = myObj.DoIt(a);
SpecialClass1 c = myObj.DoThat(a);

Как видим, далее вы переопределили свои два класса и назвали их B и Extended.
Я же, используя свой "шаблон проектного наследования" (назовём так. т.е. наследуется целый проект
из N классов <-> к аналогичному множеству из N классов).
Потому переименую B и Extended - в OtherClass1, OtherClass2.

Т.е. OtherProject.dll : код определяющий <связное множество OtherClass1, OtherClass2, Other... >

Как будут определены эти классы, т.е. унаследование целого проекта, об этом ниже, а пока глядя на ваш код,
после создания этого проекта, ваш вызываемый код будет таким (сравните с премером выше) -


C#
1
2
3
4
5
6
OtherClass1 a = new OtherClass1();   // аналог вашего B b = new B();
SpecialClass2 myObj = new OtherClass2();  // аналог вашего  Original extended = new Extended();
myObj.field = a;   //  это моё 
 
OtherClass1  b =myObj.DoIt(a);      //  это виртуальный 
OtherClass1  c = ((OtherClass2) myObj).DoThat(a); //  это невиртуальный метод
Я именно - разобрал ваш пример, применительно к моей стратегии! Немного своего добавил.
И что мы видим?
То, что аналог вашего подхода (обычное наследование) -приводит к тому, что в используемом коде,
(exe) - проекта OtherProject.dll , который наследован от SpecialProject.dll --
в каких то местах, применяется слово Other, а в каких то по прежнему Special !

Вот именно это и не устраивает. Парадигма моего "шаблона проектного наследования",
такая, чтобы любой внешний код, использующий связное множество классов,
<связное множество SpecialClass1, SpecialClass2, Special... >
полностью был работоспособным, при замене всех определений в этом множестве, т.е. при замене всех
'Special' на 'Other' !
(Никаких приведений типов! Никаких использований "в одном месте Special, в другом -Other " .. )

Т.е. вот именно такой (применительно к данному случаю) должен быть код внешнего проекта, т.е.
Код для exe -- код использующий <связное множество OtherClass1, OtherClass2, Other... >

C#
1
2
3
4
5
6
7
OtherClass1 a = new OtherClass1();   // аналог вашего B b = new B();
OtherClass2 myObj = new OtherClass2();  // аналог вашего  Original extended = new Extended();
myObj.field = a;   //  это моё 
 
OtherClass1  b =myObj.DoIt(a);      //  это виртуальный. Должен вызваться переопределенный метод у  OtherClass2 
OtherClass1  c =myObj.DoThat(a); 
     //  это невиртуальный метод.  Должен вызваться метод у OtherClass2, а в нем: также может быть base.DoThat(a);

Разобранный случай, с двумя классами самый простой, но вообще в таком шаблоне проектирования, будь экзешник
использовать хоть любые N классов из проекта SpecialProject.dll, после создания другого унаследованного
проекта OtherProject.dll, нужно так - чтобы во внешнем коде,
было достаточно автоматически (даже автогенератором кода) заменить все слова 'Special' на 'Other' - и
всё должно работать.

Также еще интересная особенность - если в вышеописанном случае, сделать SpecialProject.dll -->
в BasedProject.dll (т.е. просто переименовать все слова Special на Based),
а в новом проекте OtherProject.dll переименовать слова Other на Special -
то выходит, даже без перекомпиляции внешнего кода (к которому может и не быть доступа вообще) -
подложив новую dll - мы заставим exe-файл работать по-другому, с некими другими возможностями.


Правильно я всё описал? Надеюсь, теперь понятно.

Итак, что же мы пропустили? А пропустили, описание нашего нового проекта. Псевдокод получается,
должен быть таким.


OtherProject.dll : код определяющий <связное множество OtherClass1, OtherClass2, Other... >

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class OtherClass1  :   SpecialClass1 
{
        //public int field;  // это поле унаследовалось, значит в этом классе тоже присутствует 
        public int field2; 
}
 
 
public class OtherClass2 : SpecialClass2 
{
        public OtherClass1 field;   //  это поле унаследовалось,  но также, еще и тип изменился на производный  
                                             //  (плодить новые поля и проигрывать по памяти, там где это можно не делать - нельзя ) 
                                            // псевдокод, может быть такой: 
                                            // public OtherClass1 field  :  SpecialClass1  field  ;
 
        private int tt;  //  а это поле не наследуется, оно новое.  Потому что оно  не типа  SpecialClass1 
 
                  // виртуальный. При использовании ссылки на базовый класс, вызовется 
                  //  именно этот метод!   И при этом сигнатура здесь другая!  
                  // public override OtherClass1  DoIt (OtherClass1  input)    :  SpecialClass1  DoIt (SpecialClass1  input)  
        public override OtherClass1  DoIt (OtherClass1  input)  
        {
            //  
        }
 
        public OtherClass1   DoThat (OtherClass1  input)  // невиртуальный
        {
            SpecialClass1  intermediateObj =  base.DoThat ((SpecialClass1) input);
            //....   +  дописали  что то своё новое! 
        }
}


Если понятен псевдокод, и кто-то считает, что подобного на C# сделать нельзя, я спорить не буду,
потому что пока еще не разбирал такие возможности.
Но на C++ это сделать можно!

И вот, в первом старт-посте этой темы, я это подробно и описал.

Там у меня, от ModulePosition унаследовался сначала SpecialPosition .

Затем от ModuleDrive (для него использовался шаблон+typedef)
---> сначала унаследовался через свойство КОВАРИАНТНОСТИ - класс TemplateDrive<SpecialPosition>,
а уже от него - класс SpecialDrive.

В конечном итоге, и SpecialDrive - наследник ModuleDrive , и всё что у него внутри определено
как SpecialPosition - имеет в базовом классе тип ModulePosition . И поля, и сигнатуры методов,
и даже испольования переменных в методах можно сделать.

Таким образом, доводя стратегия дальше, можно целое множество классов в проекте, к примеру

[SpecialPosition+SpecialDrive+SpecialAlgo rithmik+SpecialController + Special ... другие классы] -> dll
унаследовать от
[ModulePosition+ModuleDrive+ModuleAlgorit hmik+ModuleController + Module ... другие классы] -> dll

и любой внешний проект (EXE), который ранее работал "над множеством" ModuleProject.dll,
будет работать "над множеством" "расширенного" специализированного SpecialProject.dll,
путем простой замены в его коде идентификаторов-слов - Module - на Special.

Чтобы код внешнего проекта даже не перекомпилировать - делаем старый ModuleProject.dll -> в OldbaseProject.dll ,
а новый SpecialProject.dll --> в ModuleProject.dll.

И EXE должен заработать с другими расширенными возможностями и алгоритмами.

Этот шаблон проектирования я и называю, "шаблон проектного наследования", т.е. наследуется
целый ПРОЕКТ, из N-связных классов, а не отдельный класс.

Что есть код? Возьмем язык C#, он состоит из операторов, ключевых слов и т.д.
Значит код на C# - это некая программа, использующая
множество [+-*/ | & ... class struct public ... и т.д. ключевые слова ]

Допустим я создал проект, из множества классов. Внешний код, используемый его, будет
использовать Тьюринг-полный язык C# + множество новых возможностей, описанных в этом dll, т.е.
множестве определений,
[SpecialPosition+SpecialDrive+SpecialAlgo rithmik+SpecialController + Special ... другие классы как ключевые слова] -> dll

Это как бы получается, "расширение возможностей C#". (без ArrayList и Hashtable и C# был бы не тем, чем он является).
Значит, подменив dll с новым проектом, любой код ранее написанный для старого
dll будет полностью переносимым + получит новые свойства.

Допустим, SpecialProject.dll используется для решения некой переборной задачи.
(расселить студентов в общагах с условиями, расставить коней на шахматной доске или какой то другой подобной. )

Можно заметить что многие алгоритмы, использующиеся для решения переборных задач, в чем-то идентичны.
Затем был написан некий ВНЕШНИЙ код (EXE), его используемый (это может быть всё что угодно- редизайн , работа с этим проектом SpecialProject.dll и т.д.).

Затем появилась некая другая переборная задача - OtherProject.dll
"шаблон проектного наследования", который я тут выдумываю, позволит разработать этот OtherProject,
так, чтобы средствами C#, его можно было использовать полностью аналогично проекту SpecialProject.dll .

Код использования может быть точно таким же, за исключением замены всех слов-приставок в множестве связных
классов проекта, (Special на Other).
И эстетическая красота подобного решения завораживает.

Ну, вроде расписал понятно. После внимательного прочтения, может быть теперь любой сможет понять?

Добавлено через 37 минут
Фактически, подобное решение, можно сделать и без "шаблона проектного наследования"
и даже и вовсе без наследования.
Но в таком случае, будет следующее "плохое последствие" - дублирование кода.
Если при разработке обнаружится баг, то менять надо будет в обоих проектах,
кроме того, поддержка проектов - тоже уже для двух (надо увеличивать ресурсы поддержки).
А если таких проектов раплодится 5-10 - В десяти местах дублировать код.
0
Эксперт .NET
 Аватар для Usaga
14139 / 9368 / 1350
Регистрация: 21.01.2016
Сообщений: 35,267
09.11.2017, 17:01
SergeyYN, для какой цели вы делаете это, а потом говорите, что оно вам не нравится:
C#
1
OtherClass1  c = ((OtherClass2) myObj).DoThat(a);
Вы не знаете, что ссылка на базовый класс может указывать на класс-наследник? При этом вы этот код мне приписываете, хотя я продемонстрировал, что этого делать не надо.

Добавлено через 1 минуту
Остальное читать не стал) Портянка какая-то)
0
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
09.11.2017, 17:23  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
то ссылка на базовый класс может указывать на класс-наследник?
Может. Но это метод невиртуальный. А потому используя ссылку на базовый - там и вызовется метод базового.
В этой же строке нужно вызвать метод наследника (который у себя внутри может вызвать метод базового
через base.DoThat(a); + дальше сделать что то своё новое.)


Цитата Сообщение от Usaga Посмотреть сообщение
При этом вы этот код мне приписываете
Да, именно так. Приведенный код - аналог вашего
(только классы переименовал приведя к своей системе + что то своё добавил. А метод DoThat - мой добавленный,
не ваш).

Остальное читать не стал
Чтобы понять, что нового в шаблоне проектирования , надо внимательно читать.
0
Эксперт .NET
 Аватар для Usaga
14139 / 9368 / 1350
Регистрация: 21.01.2016
Сообщений: 35,267
10.11.2017, 13:40
Цитата Сообщение от SergeyYN Посмотреть сообщение
Чтобы понять, что нового в шаблоне проектирования , надо внимательно читать.
Я не увидел проблемы. Не смог разглядеть за стеной несодержательного текста, извините. Соответственно, не увидел я и где тут "новый шаблон", в чём он новый и шаблон ли вообще.

Вы можете сжато и ясно изложить суть проблемы? Если нет, то ничего страшного.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
10.11.2017, 13:40
Помогаю со студенческими работами здесь

Можно ли считать шаблон Windows Form реализацией шаблона проектирования MVC
Возник вопрос, можно ли считать шаблон, который мы получаем при создании проекта Windows Form реализацией шаблона проектирования MVC...

Что это такое и как это можно сделать?
Это что то из стандартных компонентов или как в своем проекте сделать что то подобное? подразумевается пока не нажал окно скрыто, нажал,...

нужно создать таблицу из 3 строк и 4 столбцов и заполнить её (любой информацией,это неважно) . Как это можно сделать ?
Здравствуйте.У меня возникла проблема. Помогите пожалуйста!Модуль в понедельник , про таблицы ничего не рассказывали , а преподаватель...

Как можно определить какой это драйвер?
Как можно определить какой это драйвер??? : http://www.****************/images/41959_kak_ponyat.JPG &quot;неизвестное...

Можно ли на планшете вместо 8ки поставить 7ку? Как это можно сделать?
Здравствуйте! Такой вот вопросик: Кто-то сталкивался с переустановкой винды на планшетах? Если да, то возможно ли это? И что нужно делать,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru