Здравствуйте, <Аноним>, Вы писали:
А>Есть стандартный контрол ... (вообще говоря, их несколько, но для примера сойдёт любой, причём какой конкретно — неважно). А>Надо сделать его красивым (добавить рамочку, картинки, эффекты...) и к тому-же содержащим особенную исключительно для разрабатываемого приложения функциональность. Как лучше поступить (в плане иерархии классов)?
Вам нужен паттерн Decorator. Но лучше почитать GOF — там как раз ваш случай.
... << RSDN@Home 1.1.4 beta 4 rev. 310>>
"Develop with pleasure!"
Красивый и особенный или особенный и красивый?
От:
Аноним
Дата:
21.02.05 13:27
Оценка:
Есть стандартный контрол ... (вообще говоря, их несколько, но для примера сойдёт любой, причём какой конкретно — неважно).
Надо сделать его красивым (добавить рамочку, картинки, эффекты...) и к тому-же содержащим особенную исключительно для разрабатываемого приложения функциональность. Как лучше поступить (в плане иерархии классов)?
Сontrol
BeautyControl
SpecialBeautyControl
или
Control
SpecialControl
BeautySpecialControl
или
Control
SpecialBeautyControl
Лично я склоняюсь к первому варианту, но хотелось бы услышать ещё чьё-то мнение...
08.03.05 14:54: Перенесено модератором из '.NET GUI' — AndrewVK
Я бы вообще так не делал... и уж точно не первый варант. Иначе получится, что SpecialControl в природе вообще не сможет существовать... Кроме того, если BeautyControl будет в иерархии, то SpecialControl кастомизировать будет сложнее, поскольку придется раздувать иерахию.
Думаю, что лучше вообще вынести эту логику куда-нить. Можно, например, параметризовать SpecialControl классом наводящим красоту... так Вы получите дополнительную гибкость.
В таких случаях удобно использовать компонентный подход,который позволяет сделать взаимодействие разных частей программы прозрачныи и максимально гибким. При этом связность частей проекта минимальная.
Например, в конроле в какой-то момент требуется применить к рисунку определенный эффект. Для этого контрол обращается к контейнеру за сервисом и вызывает необходимый эффект.
class MyControl
{
private void ApplyBlur(Image img)
{
if(this.Site != null)
{
// см. метод MyForm.GetService
Effects ef = this.Site.GetService(typeof(Effects)) as Effects;
if(ef != null)
ef.Blur(imt);
}
}
}
Теперь как это работает:
class MyForm : Form
{
// этот метод предоставляет сервисы для MyControl
protected override object GetService(Type service)
{
if(service == typeof(Effects))
{
// в зависимости от чего-то возвращать разных наследников Effects
switch(....)
{
case "...":
return _Fast;
class Effects
{
public virtual Image Blur(Image img)
{
...
}
}
class FastEffects : Effects
{
public override Image Blur(Image img)
{
...
}
}
class HiFiEffects : Effects
{
public override Image Blur(Image img)
{
...
}
}
Остается только создать MyControl, и добавить его в MyForm:
MyControl mc = new MyControl();
mc.Parent = this; // MyForm this.Components.Add(mc); // с этого момента можно обращаться к MyControl.Site, до этого он был null;
Можно не использовать MyForm как контейнер, а сделать так:
class MyApp
{
private class MyContainer : Container
{
// сюда перенести метод GetService из MyForm
}
public static MyContainer _MyContainer = new MyContainer();
[STAThread]
static void Main()
{
MyForm frm = new MyForm();
frm.ControlAdded += new ControlEventHandler(frm_ControlAdded);
Application.Run(frm);
}
И самое интересное, что в любой момент можно MyControl удалить из MyContainer и поместить в другой контейнер, в котором переопределенный GetService реализует другую логику.
Re[2]: Красивый и особенный или особенный и красивый?
От:
Аноним
Дата:
24.02.05 09:38
Оценка:
O>Вам нужен паттерн Decorator. Но лучше почитать GOF — там как раз ваш случай.
Почитал, спасибо..
Если можно, ещё несколько глупых вопросов :)
Для правильной реализации этого шаблона в .NET мне надо, чтобы мой декоратор наследовал Control?
Получаем иерархию:
Control
Button //
Toolbar // некоторые из контролов, которым нужна общая дополнительная функциональность
ToolbarButton //
Decorator // использует Control
BeautyDecorator // рамка, картинка, бла-бла-бла
SpecialDecorator // специальная функциональность
В рантайме у меня будет объект SpecialDecorator со ссылкой на BeautyDecorator и далее со ссылкой на Button — всё хорошо, со ссылкой на ToolbarButton — проблема. Не могу положить декоратор на Toolbar — могу только ToolbarButton... правильны ли мои выкладки и есть ли решение?
Если положить декорируемый объект... Может, обрабатывать события декорируемого объекта и делать что-то по ним (рисовать рамку, например)? Где-то держать ссылки на все декораторы чтобы GC их не снёс случайно? Да и как я тогда узнаю, на каком уровне вложенности его искать?
Re: Красивый и особенный или особенный и красивый?
От:
Аноним
Дата:
24.02.05 10:33
Оценка:
Здравствуйте, Аноним, Вы писали:
А>В таких случаях удобно использовать компонентный подход,который позволяет сделать взаимодействие разных частей программы прозрачныи и максимально гибким. При этом связность частей проекта минимальная.
Эээ.. тоесть, в каждом контейнере, куда я могу захотеть положить этот свой красивый особенный контрол (форма, панель, тулбар, другая форма, ...), должен быть реализован тот метод, где switch, и везде одинаковый? Хотя можно конечно сделать EffectsFactory, но мне придётся унаследовать каждый класс, который может служить контейнером для контрола и дополнить этот метод вызовом к ней? Или как?
Re: Красивый и особенный или особенный и красивый?
От:
Аноним
Дата:
09.03.05 16:23
Оценка:
> Или как?
// Используется в контролах для создания разных эффектов.
// (эффекты определяется в ControlSkin)
public interface IEffects
{
void Blur(Graphics g);
}
// Предоставляет контролам доступ к эффектам, т.е. к реализации IEffects
public class ControlSkin : System.ComponentModel.Container
{
public static void AttachTo(Control value)
{
if (_ControlSkin == null)
_ControlSkin = new ControlSkin();
// это одна из реализаций, но контролу легко предоставить другую реализацию (см. выше GetService) private class HiFiEffects : IEffects
{
public void Blur(Graphics g)
{
throw new NotImplementedException();
}
}
}
// контрол, которому требуются эффекты
public class SkinControl : UserControl
{
public SkinControl()
{
}
// ссылку на сервис можно кешировать,
// а такой способ приведен для примера
IEffects effect = (IEffects)this.Site.GetService(typeof(IEffects));
effect.Blur(e.Graphics);
}
}
Теперь после создания контрола, можно в любой момент вызвать ControlSkin.AttachTo(контрол).
Можно сделать несколько контейнеров подобных ControlSkin с разными эффектами. И в любой момент можно вызвать, например, BestSkin.AttachTo(контрол) и сразу подключаться новые эффекты.
Здравствуйте, Аноним, Вы писали:
А>Есть стандартный контрол ... (вообще говоря, их несколько, но для примера сойдёт любой, причём какой конкретно — неважно). А>Надо сделать его красивым (добавить рамочку, картинки, эффекты...) и к тому-же содержащим особенную исключительно для разрабатываемого приложения функциональность. Как лучше поступить (в плане иерархии классов)?
А>Лично я склоняюсь к первому варианту, но хотелось бы услышать ещё чьё-то мнение...
А мне вообще кажется, что имя лучше строить по принципу Предок-дальний->Предок-ближний->СамКонтрол
Тобишь Control...
Кстати Special и Beauty — ИМХО неподходящие слова для описания функциональных особенностей класса (даже если это просто замена метода прорисовки). Имя должно явно описывать круг уточнений по отношению к ближайшему значимому (не промежуточному) предку в двух словах.
Other ideas?