A szoftverfejlesztésben a blackboard minta egy viselkedési minta, ami számítási keretrendszert biztosít a tervezéshez és olyan rendszerek implementálásához, amik nagy és különböző specializált modulokat integráltak, és komplex, nem determinisztikus stratégiát valósít meg. Ezt a mintát a HEARSAY-II projekt tagjai alkották, és először hangfelismeréshez használták.
Szerkezete A blackboard modellnek három fő összetevője van: blackboard (Blackboard) - egy strukturált globális memória, ami a megoldás objektumait tartalmazza tudásbázis (Knowledge Sources)- magasan specializált modulok a saját reprezentációjukkal együtt vezérlő összetevők (Control) - selectek, konfigurációk és tudásbázisok futtatása.
Implementáció Első lépés, hogy tervezzük meg a megoldás terét, ami a blackboard struktúra definíciójához vezet. Aztán, a tudásbázist kell elkészíteni. Ez a két lépés nagyon összefüggő.
A következő lépés, a vezérlők meghatározása, ami általában komplex ütemezés formájában létezik, ami domain-specifikus heurisztikákat használ, hogy rangsorolja a végrehajtható tudásbázist.
középre|System Structure
Ismert felhasználásai beszédfelismerés jármű azonosítás és követés protein molekulák struktúrájának azonosítása szonár jelek elemzése
Következmények A blackboard minta hatékony megoldást biztosít olyan komplex rendszerek tervezéséhez és implementálásához, ahol heterogén modulok dinamikus kombinációjával oldjuk meg a problémát. Ez biztosít olyan nem funkcionális tulajdonságokat mint: újrafelhasználhatóság változtathatóság robusztusság
A blackboard minta megengedi, hogy a processzek szorosan együtt működhessenek különböző szálakon, és reagáljanak, ha kell.
Példák Radar védelmi rendszer minta (C#-ban).
Kód a MainWindow.xaml: <ListBox ItemsSource="{Binding blackboard.CurrentObjects}" ItemsPanel="{DynamicResource ItemsPanelTemplate1}" ItemContainerStyle="{DynamicResource ItemContainerStyle}" ItemTemplate="{DynamicResource ItemTemplate}" Margin="20,20,20,10" Foreground="#FFDE6C6C" > <ListBox.Resources> <ItemsPanelTemplate x:Key="ItemsPanelTemplate1"> <Canvas IsItemsHost="True"/> </ItemsPanelTemplate>
Kód az item container helymeghatározásához <Style x:Key="ItemContainerStyle" TargetType="{x:Type ListBoxItem}"> <Setter Property="Background" Value="Transparent"/> <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/> <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/> <Setter Property="Canvas.Left" Value="{Binding X}"/> <Setter Property="Canvas.Top" Value="{Binding Y}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBoxItem}"> <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true"> <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
Kód az Item-hez (ItemTemplate definiálja az objektumot, egy Image és TextBox-ok): <DataTemplate x:Key="ItemTemplate"> <Border> <Border.Style> <Style TargetType="{x:Type Border}"> <Style.Triggers> <DataTrigger Binding="{Binding IsThreat}" Value="true"> <Setter Property="Background" Value="Red"/> </DataTrigger> <DataTrigger Binding="{Binding IsThreat}" Value="false"> <Setter Property="Background" Value="Green"/> </DataTrigger> </Style.Triggers> </Style> </Border.Style> <Grid Margin="3"> <Image Height="48" Source="{Binding Image}" /> <StackPanel Margin="0,0,0,-30" VerticalAlignment="Bottom" > <TextBlock Text="{Binding Type}"/> <TextBlock Text="{Binding Name}"/> </StackPanel> <TextBlock HorizontalAlignment="Right" TextWrapping="Wrap" Text="{Binding DistanceFromDestruction}" VerticalAlignment="Bottom" Width="Auto" Visibility="{Binding IsThreat, Converter={StaticResource BooleanToVisibilityConverter}}"/> </Grid> </Border> </DataTemplate> Kód a Blackboard komponens mögött MVVM ViewModel implementációjában:
public Blackboard blackboard { get; set; } Controller controller;
public MainWindow() { InitializeComponent(); DataContext = this;
blackboard = new Blackboard(); controller = new Controller(blackboard);
A Controller mögötti kód: private void Button_Click(object sender, System.Windows.RoutedEventArgs e) { controller.AddSignalProcessor(); }
Kód a base class IObject-hez: public interface IObject { ObjectType Type { get; set; } string Name { get; set; } WriteableBitmap Image { get; set; } bool? IsThreat { get; set; } ProcessingStage Stage { get; set; } int X { get; set; } int Y { get; set; }
IObject Clone(); } Kód a radar module-ban: AllObjects = new List<IObject> { new BirdObject(ObjectType.Bird, "", new WriteableBitmap(new System.Windows.Media.Imaging.BitmapImage(new Uri(@"pack://application:,,,/Media/Bird.bmp", UriKind.Absolute))), false, false), new PlaneObject(ObjectType.Plane, "", new WriteableBitmap(new System.Windows.Media.Imaging.BitmapImage(new Uri(@"pack://application:,,,/Media/Plane.bmp", UriKind.Absolute))), false, false), new RocketObject(ObjectType.Rocket, "", new WriteableBitmap(new System.Windows.Media.Imaging.BitmapImage(new Uri(@"pack://application:,,,/Media/Rocket.bmp", UriKind.Absolute))), false, false),
Kód ami a beérkező objektumokat kezeli: public IncomingObject(IObject obj) : base(ObjectType.Unknown, null, null, true, null) { actualObject = obj; ProcessedPixels = new bool[16, 16];
//Paint the image as all red to start with Image = new WriteableBitmap(48, 48, 72, 72, PixelFormats.Bgr32, null); int[] ary = new int[(48 * 48)]; for (var x = 0; x < 48; x++) for (var y = 0; y < 48; y++) ary[48 * y + x] = 255 * 256 * 256; Image.WritePixels(new Int32Rect(0, 0, 48, 48), ary, 4 * 48, 0); }
Kód a tudásbázis interfészéhez: public interface IKnowledgeSource { bool IsEnabled { get; } void Configure(Blackboard board); void ExecuteAction();
KnowledgeSourceType KSType { get; } KnowledgeSourcePriority Priority { get; } void Stop(); }
A jel processor implementálásához: public override bool IsEnabled { get
for (var ix = 0; ix < blackboard.CurrentObjects.Count(); ix++) if (blackboard.CurrentObjects[ix].Stage < ProcessingStage.Analysed) return true;
return false;
public override void ExecuteAction() { for (var ix = 0; ix < blackboard.CurrentObjects.Count(); ix++) if (blackboard.CurrentObjects[ix].Stage < ProcessingStage.Analysed) ProcessAnotherBit(blackboard.CurrentObjects[ix]); }
void ProcessAnotherBit(IObject obj) { int GRANULARITY = 16; int blockWidth = obj.Image.PixelWidth / GRANULARITY;
kódrészlet writablebitmaps-ok közti másoláshoz: int stride = obj.Image.PixelWidth * obj.Image.Format.BitsPerPixel / 8; int byteSize = stride * obj.Image.PixelHeight * obj.Image.Format.BitsPerPixel / 8; var ary = new byte[byteSize]; obj.Image.CopyPixels(ary, stride, 0); var unk = obj as IncomingObject; unk.GetActualObject().Image.CopyPixels(aryOrig, stride, 0);
for (var iy = 0; iy < blockWidth; iy++) { for (var ix = 0; ix < blockWidth; ix++) for (var b = 0; b < 4; b++)
ary[curix] = aryOrig[curix]; curix++;
curix = curix + stride - (blockWidth * 4); }
obj.Image.WritePixels(new Int32Rect(0, 0, obj.Image.PixelWidth, obj.Image.PixelHeight), ary, stride, 0);
Kód a pixelek összehasonlításához a képfelismerésnél: for (var ix = 0; ix < blockWidth; ix++) { var argb1 = (ary[curix + 1] * 256 * 256) + (ary[curix + 2] * 256) + ary[curix + 3]; var argb2 = (aryKnown[curix + 1] * 256 * 256) + (aryKnown[curix + 2] * 256) + aryKnown[curix + 3]; if (argb1 != 255 * 256 * 256 && argb1 != argb2)
nomatch = true; break;
curix += 4; }
if (matches.Count() == 1) { obj.Type = matches.Type; obj.Name = matches.Name; obj.IsThreat = matches.IsThreat;
obj.Image = new WriteableBitmap(matches.Image); //Create new image instance
if (obj.Type != ObjectType.Plane) obj.Stage = ProcessingStage.Identified; else obj.Stage = ProcessingStage.Analysed; }
Kód a repülő azonosításhoz: for (var ix = 0; ix < blackboard.CurrentObjects.Count(); ix++) { var obj = blackboard.CurrentObjects[ix]; if (obj.Stage == ProcessingStage.Analysed && obj.Type == ObjectType.Plane)
var unk = obj as IncomingObject; var actual = unk.GetActualObject(); obj.Name = actual.Name; obj.IsThreat = actual.IsThreat; obj.Stage = ProcessingStage.Identified;
Kód a harcigépekhez: public override void ExecuteAction() { for (var ix = 0; ix < blackboard.CurrentObjects.Count(); ix++)
var obj = blackboard.CurrentObjects[ix] as IncomingObject; if (obj.IsThreat != null && obj.IsThreat.Value && (obj.Stage != ProcessingStage.Actioned))
if (obj.MoveHitsTarget()) DestroyTarget(obj);
private void DestroyTarget(IncomingObject obj) { int stride = obj.Image.PixelWidth * obj.Image.Format.BitsPerPixel / 8; int byteSize = stride * obj.Image.PixelHeight * obj.Image.Format.BitsPerPixel / 8; var ary = new byte[byteSize]; obj.Image.CopyPixels(ary, stride, 0);
DrawCross(stride, ary);
obj.Image.WritePixels(new Int32Rect(0, 0, obj.Image.PixelWidth, obj.Image.PixelHeight), ary, stride, 0); obj.Stage = ProcessingStage.Actioned; }
private static void DrawCross(int stride, byte[] ary) { for (var y = 1; y < 47; y++)
var line1Pos = (y * stride) + (y * 4); var line2Pos = (y * stride) + (stride - 4) - (y * 4); for (var a = -1; a < 2; a++)
ary[line1Pos + 4 + (a * 4)] = ary[line2Pos + 4 + (a * 4)] = 255; ary[line1Pos + 5 + (a * 4)] = ary[line2Pos + 5 + (a * 4)] = 0; ary[line1Pos + 6 + (a * 4)] = ary[line2Pos + 6 + (a * 4)] = 0; ary[line1Pos + 7 + (a * 4)] = ary[line2Pos + 7 + (a * 4)] = 0;
Kapcsolódó cikkek Programtervezési minta
Jegyzetek
Fordítás
Kategória:Programtervezési minták