• Nie Znaleziono Wyników

Wzorce projektowe 3

N/A
N/A
Protected

Academic year: 2021

Share "Wzorce projektowe 3"

Copied!
78
0
0

Pełen tekst

(1)

Wzorce projektowe 3

Marcin Orchel

AGH University of Science and Technology in Poland

1 / 78

(2)

Agenda

(3)

1 Wzorce współbieżności

2 Wzorce architektoniczne

3 Pozostałe wzorce

Agenda 3 / 78

(4)

Wzorce współbieżności

(5)

Pamięć lokalna wątku (ang. thread-local storage)

metoda do przypisania pamięci statycznej lokalnie dla wątku, java.lang.ThreadLocal<T>

Wzorce współbieżności 5 / 78

(6)

Pamięć lokalna wątku

import java.util.concurrent.atomic.AtomicInteger;

public class ThreadId {

// Atomic integer containing the next thread ID to be assigned

private static final AtomicInteger nextId = new AtomicInteger(0);

// Thread local variable containing each thread’s ID private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>() {

@Override protected Integer initialValue() { return nextId.getAndIncrement();}

};

// Returns the current thread’s unique ID, assigning it if necessary

public static int get() { return threadId.get();

} }

Wzorce współbieżności 6 / 78

(7)

Reaktor (ang. reactor )

demultipleksowanie i rozdzielanie żądań, które są dostarczane do aplikacji od jednego, lub wielu klientów

dostarcza asynchronicznyinterfejs do zasobów, do których dostęp musi być synchronizowany

procedura obsługi zdarzenia jest powiązana z zasobem struktura wzorca Reaktor odwraca sterowanie w aplikacji

Wzorce współbieżności 7 / 78

(8)

Reaktor

Reactor handleEvents() registerHandler() removeHandler()

Handle

Event Handler handleEvent() getHandle()

Concrete Event Handler A handleEvent()

getHandle() Synchronous Event Demultiplexer

select()

Concrete Event Handler B handleEvent()

getHandle() dispatches

owns notifies handle set

Rysunek 1:Źródło: własne

Wzorce współbieżności 8 / 78

(9)

Reaktor

Reactor obsługuje rejestrację i wyrejestrowanie procedur obsługi zdarzeń. Reactor zawiera zbiór uchwytów do zasobów (handle set).

Reactor dla zasobu z demultipleksera, w którym nastąpiło zdarzenie (zasób aktywny) wywołuje procedurę obsługi zdarzenia.

metoda handleEvents dla zasobów z nowymi danymi (sprawdzenie przez demultiplexer) wywołuje procedurę obsługi dla tych danych sekwencyjniei ustawia zasób na nieaktywny.

Pętla zdarzeniowa (ang. event loop) w metodzie select w Synchronous Event Demultiplexer wyszukuje wszystkie uchwyty do zasobów, które są aktywne. Zasoby nie są blokowane.

Event Handler: procedura obsługi zdarzeń i powiązany z nią uchwyt do zasobu (Handle)

Wzorce współbieżności 9 / 78

(10)

Reaktor

public interface EventHandler {

void handleEvent(byte[] data);

Socket getHandler();

}

public interface SynchronousEventDemultiplexer {

List<Socket> select(Collection<Socket> listeners);

}

public interface Reactor {

void registerHandle(EventHandler eventHandler);

void removeHandle(EventHandler eventHandler);

void handleEvents();

}

(11)

Reaktor

public class MessageEventHandler implements EventHandler {

private Socket socket;

public MessageEventHandler(String ipAddress, int port) {

socket = new Socket(ipAddress, port);

}

public void handleEvent(byte[] data) {

String message = Encoding.UTF8.getString(data);

}

public Socket getHandler() {

return socket;

} }

Wzorce współbieżności 11 / 78

(12)

Reaktor

public class DefaultSynchronousEventDemultiplexer implements SynchronousEventDemultiplexer {

public List<Socket> select(Collection<Socket> sockets) {

List<Socket> activeSockets = new ArrayList<Socket>();

for(Socket socket : sockets) { if (socket.pending())

{

activeSockets.add(socket);

} }

return activeSockets;

} }

(13)

Reaktor

public class DefaultReactor implements Reactor { private SynchronousEventDemultiplexer

synchronousEventDemultiplexer;

private Map<Socket, EventHandler> handlers;

public Reactor(SynchronousEventDemultiplexer synchronousEventDemultiplexer)

{

this.synchronousEventDemultiplexer = synchronousEventDemultiplexer;

handlers = new HashMap<TcpListener, IEventHandler>();

}

public void registerHandle(EventHandler eventHandler) {

handlers.add(eventHandler.getHandler(), eventHandler);

}

Wzorce współbieżności 13 / 78

(14)

Reaktor

public void removeHandle(EventHandler eventHandler) { handlers.remove(eventHandler.getHandler());

}

public void handleEvents() { while (true) {

List<Socket> sockets =

synchronousEventDemultiplexer.select(handlers.keySet());

for (Socket socket : sockets) { int dataReceived = 0;

byte[] buffer = new byte[1];

List<Byte> data = new List<Byte>();

Socket socket = socket.acceptSocket();

do {

dataReceived = socket.receive(buffer);

(15)

Reaktor

if (dataReceived > 0) {

data.add(buffer[0]);

}

} while (dataReceived > 0);

socket.close();

handlers[socket].handleEvent(data.toArray());

} } }

Wzorce współbieżności 15 / 78

(16)

Reaktor

class Program {

static void main(string[] args) { EventHandler client1 = new

MessageEventHandler("1.1.1.1", 123);

EventHandler client2 = new

MessageEventHandler("2.2.2.2", 123);

EventHandler client3 = new

MessageEventHandler("3.3.3.3", 123);

SynchronousEventDemultiplexer synchronousEventDemultiplexer = new DefaultSynchronousEventDemultiplexer();

Reactor dispatcher = new

DefaultReactor(synchronousEventDemultiplexer);

dispatcher.registerHandle(client1);

dispatcher.registerHandle(client2);

dispatcher.registerHandle(client3);

dispatcher.handleEvents();

} }

Wzorce współbieżności 16 / 78

(17)

Observer Pattern vs Reactor Pattern

w Reaktorze mamy centralną obsługę żądań, w obserwatorze, każdy obserwator jest powiązany z podmiotem

Wzorce współbieżności 17 / 78

(18)

Aktywny obiekt (ang. active object)

oddzieleniewykonywania metody od wywołania metody w celu usprawnienia wielowątkowości i uproszczenia dostępu równoległego do obiektów, które rezydują w swoich własnych wątkach kontrolujących.

Celem jest użycie aynchronicznego wywołania metodi schedulera

(19)

Aktywny obiekt

Client Proxy method1() methodN()

Scheduler dispatch() insert()

Future

ActiveQueue enqueue() dequeue()

MethodRequest canRun() call()

Servant method1() methodN()

ConcreteMethodRequest1 ConcreteMethodRequest2 invoke

obtain result from instantiate

instantiate

execute maintain

write to

Rysunek 2:Źródło: własne

Wzorce współbieżności 19 / 78

(20)

Servant

class Servant {

MQ_Servant (size_t mq_size);

// Message queue implementation operations.

void put (Message msg);

Message get ();

// Predicates.

boolean empty ();

boolean full ();

// Internal queue representation, e.g., a circular // array or a linked list, that does not use any // internal synchronization mechanism.

};

(21)

Proxy

class Proxy {

// The servant that implements the active object // methods and a scheduler for the message queue.

Servant servant;

Scheduler scheduler;

// Bound the message queue size.

enum { MQ_MAX_SIZE = /* ... */ };

Proxy (size_t size = MQ_MAX_SIZE): scheduler (size), servant (size) { }

// Schedule <put> to execute on the active object.

void put (Message msg) {

MethodRequest mr = new Put (servant, msg);

scheduler.insert (mr);

}

// Return a <MessageFuture> as the "future" result of // an asynchronous <get> method on the active object.

Wzorce współbieżności 21 / 78

(22)

Proxy

MessageFuture get () { MessageFuture result;

MethodRequest mr = new Get(servant, result);

scheduler.insert (mr);

return result;

}

// empty() and full() predicate implementations ...

};

(23)

Method Request

class MethodRequest implements Runnable { // Evaluate the synchronization constraint.

boolean canRun ();

// Execute the method.

void run();

};

Wzorce współbieżności 23 / 78

(24)

Method Request

class Get extends MethodRequest { Servant servant;

MessageFuture result;

Get(Servant rep, MessageFuture f) { servant = rep;

result = f; } bool canRun() {

// Synchronization constraint: cannot call a // <get> method until queue is not empty.

return !servant.empty();

}

void run () {

// Bind dequeued message to the future result.

result.set(servant.get());

} };

(25)

Scheduler

class Scheduler {

// List of pending MethodRequests.

private BlockingQueue<Runnable> actList = new LinkedBlockingQueue<Runnable>(); // ActiveQueue Scheduler() {}

// Put <MethodRequest> into <ActiveQueue>. This // method runs in the thread of its client, i.e.

// in the proxy’s thread.

void insert (MethodRequest mr) { actList.put(mr); }

};

Wzorce współbieżności 25 / 78

(26)

Scheduler

// Dispatch the method requests on their servant // in its scheduler’s thread of control.

public void dispatch() { new Thread(

new Runnable() {

@Override

public void run() { while (true) {

try {

dispatchQueue.take().run();

} catch (InterruptedException e)

{ // okay, just terminate the dispatcher }

} } }

).start();

}

Wzorce współbieżności 26 / 78

(27)

Blokada z podwójnym zatwierdzeniem (ang. double checked locking )

optymalizacja, która sprawdza najpierw czy lock musi być zajęty, przed jego zajęciem

Wzorce współbieżności 27 / 78

(28)

Blokada z podwójnym zatwierdzeniem

// Correct but possibly expensive multithreaded version class Foo {

private Helper helper;

public synchronized Helper getHelper() { if (helper == null) {

helper = new Helper();

}

return helper;

}

// other functions and members...

}

(29)

Blokada z podwójnym zatwierdzeniem

class Foo {

private volatile Helper helper;

public Helper getHelper() { Helper result = helper;

if (result == null) { synchronized(this) {

result = helper;

if (result == null) {

helper = result = new Helper();

} } }

return result;

}

// other functions and members...

}

Wzorce współbieżności 29 / 78

(30)

Balking

wykonanie akcji na obiekcie, tylko jeśli obiekt jest w ustalonym stanie

(31)

Balking

public class Example {

private boolean jobInProgress = false;

public void job() { synchronized(this) {

if (jobInProgress) { return;

}

jobInProgress = true;

}

// Code to execute job goes here // ...

}

void jobCompleted() { synchronized(this) {

jobInProgress = false;

} } }

Wzorce współbieżności 31 / 78

(32)

Blockchain

zdecentralizowany sposób przechowywania danych

blockchain to lista bloków, każdy blok w łańcuchu ma własny cyfrowy podpis zwany hashem, zawierający cyfrowy podpis poprzedniego bloku oraz dane, np. o transakcjach

hash danego bloku jest obliczany na podstawie poprzedniego hashu oraz danych

złamanie łańcucha następuje po zmianie danych

(33)

Blockchain

public class Block { public String hash;

public String previousHash;

private String data;

private long timeStamp;

public Block(String data,String previousHash) { this.data = data;

this.previousHash = previousHash;

this.timeStamp = new Date().getTime();

} }

Wzorce współbieżności 33 / 78

(34)

Blockchain

public class StringUtil {

public static String applySha256(String input){

try {

MessageDigest digest =

MessageDigest.getInstance("SHA-256");

//Applies sha256 to our input,

byte[] hash = digest.digest(input.getBytes("UTF-8"));

StringBuffer hexString = new StringBuffer(); // This will contain hash as hexidecimal

for (int i = 0; i < hash.length; i++) {

String hex = Integer.toHexString(0xff & hash[i]);

if(hex.length() == 1) hexString.append(’0’);

hexString.append(hex);

}

return hexString.toString();

}

catch(Exception e) {

throw new RuntimeException(e);

} } }

Wzorce współbieżności 34 / 78

(35)

Blockchain

public String calculateHash() {

String calculatedhash = StringUtil.applySha256(

previousHash + Long.toString(timeStamp) + data);

return calculatedhash;

}

Wzorce współbieżności 35 / 78

(36)

Blockchain

public Block(String data,String previousHash) { this.data = data;

this.previousHash = previousHash;

this.timeStamp = new Date().getTime();

this.hash = calculateHash();

}

(37)

Blockchain

public class FooChain {

public static void main(String[] args) {

Block genesisBlock = new Block("Hi im the first block", "0");

System.out.println("Hash for block 1 : " + genesisBlock.hash);

Block secondBlock = new Block("Im the second block",genesisBlock.hash);

System.out.println("Hash for block 2 : " + secondBlock.hash);

Block thirdBlock = new Block("Im the third block",secondBlock.hash);

System.out.println("Hash for block 3 : " + thirdBlock.hash);

} }

Wzorce współbieżności 37 / 78

(38)

Blockchain

public class FooChain {

public static ArrayList<Block> blockchain = new ArrayList<Block>();

public static void main(String[] args) {

blockchain.add(new Block("Hi im the first block",

"0"));

blockchain.add(new Block("Im the second

block",blockchain.get(blockchain.size()-1).hash));

blockchain.add(new Block("Im the third

block",blockchain.get(blockchain.size()-1).hash));

String blockchainJson = new

GsonBuilder().setPrettyPrinting().create().toJson(blockchain);

System.out.println(blockchainJson);

} }

(39)

Blockchain

sprawdzanie integralności łańcucha

public static Boolean isChainValid() { Block currentBlock;

Block previousBlock;

//loop through blockchain to check hashes:

for(int i=1; i < blockchain.size(); i++) { currentBlock = blockchain.get(i);

previousBlock = blockchain.get(i-1);

//compare registered hash and calculated hash if(!currentBlock.hash.equals(

currentBlock.calculateHash()) ){

System.out.println("Current Hashes not equal");

return false; }

//compare previous hash and registered previous hash if(!previousBlock.hash.equals(

currentBlock.previousHash) ) {

System.out.println("Previous Hashes not equal");

return false;

} }

return true;

}

Wzorce współbieżności 39 / 78

(40)

Blockchain

mining blocks

public class Block { public String hash;

public String previousHash;

private String data;

private long timeStamp;

private int nonce;

(41)

Blockchain

mining blocks

public String calculateHash() {

String calculatedhash = StringUtil.applySha256(

previousHash +

Long.toString(timeStamp) + Integer.toString(nonce) + data

);

return calculatedhash;

}

Wzorce współbieżności 41 / 78

(42)

Blockchain

mining blocks

public void mineBlock(int difficulty) { String target = new String(new

char[difficulty]).replace(’\0’, ’0’); //Create a string with difficulty * "0"

while(!hash.substring( 0, difficulty).equals(target)) { nonce ++;

hash = calculateHash();

}

System.out.println("Block Mined!!! : " + hash);

}

(43)

Blockchain

mining blocks

public static void main(String[] args) {

//add our blocks to the blockchain ArrayList:

blockchain.add(new Block("Hi im the first block", "0"));

System.out.println("Trying to Mine block 1... ");

blockchain.get(0).mineBlock(difficulty);

...

Wzorce współbieżności 43 / 78

(44)

Blockchain

mining blocks

public static Boolean isChainValid() { Block currentBlock;

Block previousBlock;

String hashTarget = new String(new char[difficulty]).replace(’\0’, ’0’);

...

//loop through blockchain to check hashes:

for(int i=1; i < blockchain.size(); i++) { currentBlock = blockchain.get(i);

previousBlock = blockchain.get(i-1);

if(!currentBlock.hash.substring( 0, difficulty).equals(hashTarget)) {

System.out.println("This block hasn’t been mined");

return false; } }

(45)

Inne wzorce współbieżności

thread pool– m wątków tworzonych jest w celu rozwiązania n zadań współbieżnie

szeregowanie(ang. scheduling ) – kontrolowanie bezpośrednio kiedy wątki mogą wykonać swój kod, np. ScheduledExecutorService, lub java.util.Timer

read/write lock– dostęp wielowątkowy dla operacji odczytu, i wyłączny dla operacji zapisu, ReadWriteLock

monitor– obiekt, które metody mogą być wzajemnie wykluczane messaging pattern – umożliwia wymianę informacji pomiędzy komponentami i aplikacjami

blokada– blokada zasobu przed dostępem lub modyfikacją przez inne wątki

join

guarded suspension– oczekiwanie, aż zostanie spełniony jakiś warunek asynchronous method invocation– nie blokowanie wątku podczas oczekiwania na odpowiedź, klasa FutureTask

Wzorce współbieżności 45 / 78

(46)

Inne wzorce współbieżności

binding properties – kombinacja wielu obserwatorów w celu wymuszenia właściwości w różnych obiektach, które muszą być synchronizowane lub koordynowane w pewien sposób

master-slave – komponent główny rozdziela zadania do identycznych komponentów pobocznych i oblicza ostateczny wynik z rezultatów zwróconych przez komponenty poboczne

(47)

Wzorce architektoniczne

Wzorce architektoniczne 47 / 78

(48)

MVC

architektura MVC (ang. Model/View/Controller ) obejmuje obiekty trzech rodzajów:Modelto obiekt aplikacji,View odpowiada

prezentacji widocznej na ekranie, aController określa, jak interfejs ma reagować na działania użytkownika

Controller i View tworzą interfejs użytkownika

ustanowienie protokołu subskrypcji i powiadamiania służącego do komunikowania się między widokami i modelami (wzorzec

Obserwator)

model komunikuje się z widokami, kiedy zmienią się jego wartości, a widoki komunikują się z modelem, aby uzyskać dostęp do danych.

możliwość zagnieżdżania widoków (przyciski zagnieżdżone w panelu sterowania), traktowanie widoku złożonego w taki sam sposób jak jeden z jego komponentów (wzorzec Kompozyt)

umożliwia zmianę sposobu reagowania widoku na działania użytkownika, bez modyfikowania wizualnej warstwy prezentacji

(49)

MVC

widok korzysta z egzemplarza podklasy klasy Controller do realizowania konkretnej strategii reagowania (wzorzecStrategia) Metoda wytwórcza do określania domyślnej klasy kontrolera widoku Dekoratorw celu dodania przewijania do widoku.

Wzorce architektoniczne 49 / 78

(50)

MVC

Model coreData setOfObservers attach(Observer) detach(Observer) notify() getData() service()

Observer Update()

View myModel myController update() initialize(Model) makeController() activate() display() call update

attach, getData

Controller myModel myView update() handleEvent() initialize(Model,View) create manipulate, display

attach, call service

Rysunek 3:Źródło: własne

Wzorce architektoniczne 50 / 78

(51)

Presentation-Abstract-Control

wzorzec architektoniczny Presentation-Abstract-Control (PAC) definiuje strukturę dla interaktywnych systemów oprogramowania w formie hierarchii współpracujących agentów. Każdy agent jest

odpowiedzialny za specyficzny aspekt funkcjonalności oprogramowania i składa się z trzech komponentów: prezentacji, abstrakcji i kontroli.

Ten podział umożliwia separację interakcji z użytkownikiem, od funkcjonalności i od komunikacji z innymi agentami.

w komponencie prezentacjiznajdują się podkomponenty oferujące funkcjonalność rysowania okien, menu, dialogów i zarządzanie danymi o prezentacji. Mogą być one opakowane za pomocą wzorca fasada.

Komponent kontroli umożliwia mediację pomiędzy komponentami abstrakcji i prezentacji tak aby uniknąć powiązania między nimi. Może być zaimplementowany jako adapter. Drugą rolą komponentu kontroli jest komunikacja z innymi agentami PAC. Zdarzenia odbierane od innych agentów są przekazywane dalej, do innych agentów lub komponentu abstrakcji lub prezentacji. Ta pierwsza rola może być zaimplementowana za pomocą wzorcamediator.

Wzorce architektoniczne 51 / 78

(52)

Presentation-Abstract-Control

Rysunek 4:Źródło: wikipedia

Wzorce architektoniczne 52 / 78

(53)

Presentation-Abstract-Control

Komunikacja może być zaimplementowana wg wzorcaComposite Message. W ten sposób interfejs między agentami jest niewielki.

Agenci mogą być również połączeni za pomocą wzorcaObserwator służącego do propagacji i zmiany stanów agentów.

możemy użyć wzorca aktywnego obiektudla każdego agenta PAC, wtedy każdy agent żyje we własnym wątku

do obsługi agentów na różnych maszynach/procesach można użyć wzorzec pełnomocnikaw celu reprezentacji lokalnej innych agentów i niezależności od konkretnych maszyn

do komunikacji międzyprocesowej pomiędzy agentami można użyć wzorcówForwarder-Receiver oraz Client-Dispatcher-Server

Wzorce architektoniczne 53 / 78

(54)

PAC vs MVC

w MVC Controller służy do obsługi wejścia od użytkownika i

translacji na wewnętrzną semantykę. A więc Controller i View razem odpowiadają komponentowi prezentacji w PAC. W Controller brakuje mediacji, a także MVC nie dzieli samodzielnych podzadań systemu na współpracujących, ale luźno powiązanych agentów.

(55)

Odwrócenie sterowania (ang. Inversion of Control, IoC )

przeniesienie na zewnątrz komponentu (np. obiektu) odpowiedzialności za kontrolę wybranych czynności

przykładem wykorzystania tego wzorca jest wzorzecstrategii innym przykładem IoC może być wzorzec metody szablonowej nazywana potocznieHollywood Principle – “Don’t call us, we’ll call you”

Wzorce architektoniczne 55 / 78

(56)

Broker

wzorzec broker może być użyty do konstrukcji rozproszonych systemów oprogramowania z oddzielnymi komponentami, które komunikują się ze sobą poprzez zdalne wywołanie serwisów.

Komponent brokera jest odpowiedzialny za koordynowanie

komunikacji takiej jak przekazywanie żądań, przesyłanie rezultatów i wyjątków

(57)

Broker

Broker +mainEventLoop() +updateRepository() +registerService() +acknowledgement() +findServer() +findClient() +forwardRequest() +forwardResponse() Client-side proxy

packData() +unpackData() +sendRequest() +return()

Server-side proxy +packData() +unpackData() +callService() +sendResponse()

Client +callServer() +startTask() +useBrokerAPI()

Bridge +packData() +unpackData() +forwardMessage() +transmitMessage()

Server +initialize() +enterMainLoop() +runService() +useBrokerAPI() calls

transfers message

uses API

transfers message

calls

uses API

Rysunek 5:Źródło: własne

Wzorce architektoniczne 57 / 78

(58)

Broker

serwery implementują serwisy

klienci to aplikacje, które mają dostęp do serwisów, aby wywołać zdalny serwis klient kieruje żądanie do brokera, po zakończeniu operacji otrzymuje odpowiedź lub wyjątek od brokera

klienci nie muszą znać położenia serwerów

broker jest odpowiedzialny za przesyłanie żądań od klienta do serwera, a także odpowiedzi i wyjątków z powrotem do klienta

proxy od strony klienta ukrywa detale implementacyjne dotyczące komunikacji między klientem a brokerem, konwersji danych do wysłania, podobnie działają proxy od strony serwera

Bridge to opcjonalne komponenty służące do ukrycia detali implementacyjnych kiedy komunikuje się dwóch brokerów

(59)

Forwarder-Receiver

wzorzec dostarcza jawną komunikację międzyprocesową dla systemów oprogramowania z modelem interakcji peer-to-peer (P2P). Definiuje komponenty przekazujące i odbierające w celu oddzielenia hostów od mechanizmu komunikacyjnego

każdy host może być zarówno klientem jak i serwerem

Wzorce architektoniczne 59 / 78

(60)

Forwarder-Receiver

Peer 1 +service()

Forwarder +marshal() +deliver() +sendMsg()

Receiver +receive() +unmarshal() +receiveMsg()

Peer 2 +service()

Receiver +receive() +unmarshal() +receiveMsg()

Forwarder +marshal() +deliver() +sendMsg() sendMsg

receiveMsg

IPC IPC

receiveMsg

sendMsg

Rysunek 6:Źródło: własne

Wzorce architektoniczne 60 / 78

(61)

Client-Dispatcher-Server

wzorzec dostarcza warstwę pośrednią pomiędzy klientami i serwerami, komponent rozdzielający. Dostarcza on transparentność położenia za pomocą nazw serwisu i ukrywa szczegóły nawiązanego połączenia komunikacyjnego pomiędzy klientami i serwerami

rola klienta i serwera może zmieniać się dynamicznie

Wzorce architektoniczne 61 / 78

(62)

Client-Dispatcher-Server

Client +doTask() +sendRequest()

Dispatcher +locationMap +registerService() +unregisterServer() +locateServer() +establishChannel() +getChannel()

Server +acceptConnection() +runService() +receiveRequest()

requests connection registers, accepts link

establishes connection

request service returns result

Rysunek 7:Źródło: własne

Wzorce architektoniczne 62 / 78

(63)

Client-Dispatcher-Server

celem klienta jest wykonać zadania specyficzne dla domeny. Klient ma dostęp do operacji oferowanych przez serwery w celu wykonania przetwarzanych zadań. Przed wysłaniem żądania do serwera, klient pyta komponent rozdzielający o kanał komunikacyjny.

Serwer dostarcza listę operacji do klientów. Może sam się zarejestrować lub jest rejestrowany przez dispatchera za pomocą nazwy i adresu.

Dispatcher oferuje funkcjonalność do nawiązania kanałów komunikacyjnych

Wzorce architektoniczne 63 / 78

(64)

Composite Message

konstrukcja komunikacji między komponentami w systemie tak, że luźno powiązane komponenty tworzą minimalne założenia o

infrastrukturze komunikacji, a ściśle powiązane komponenty zajmują się ich interakcją

wzorzec koncentruje się na organizacji infrastruktury komunikacji używanej przez komponenty tak, że komponenty mogą być dodawane i usuwane z minimalnymi zmianami. W tym samym czasie narzut komunikacyjny powinien być minimalizowany.

(65)

Composite Message

Component +sendMsg() +recvMsg() +addDataSet()

DataSetInterface +size()

+add() +remove()

Message +size() +add() +remove() +marshal() +unmarshal()

DataSet +size() currentMessage

for all DataSets { find size and add;

}

Rysunek 8:Źródło: własne

Wzorce architektoniczne 65 / 78

(66)

Composite Message

komponent generuje wiadomość i może dodawać i usuwać inne zbiory danych. Niektóre komponenty mogą marshalować i dzielić na

fragmenty wiadomość do transmisji przez sieć i unmarshalować je i składać po otrzymaniu

Message to kompozyt, które może zawierać inne zbiory danych.

Message definiuje standardowe metody do dodawania lub usuwania zbiorów danych, wyznaczania rozmiarów i jeśli to konieczne metody do marshallingu, unmarshallingu, fragmentacji i łączenia

DataSet może byż dodawany lub usuwany z wiadomości przez komponent

DataSetInterface - wspólny interfejs dla DataSets i Messages

(67)

Mikrokernel (ang. Microkernel)

Mikrokernel dotyczy systemów oprogramowania, które muszą się dostosowywać do zmian w wymaganiach systemowych. Separuje minimalny funkcjonalnie rdzeń od rozszerzonych funkcjonalności i części specyficznych dla klienta. Mikrokernel jest także gniazdem do którego podłączamy rozszerzenia i koordynujemy ich współpracę.

Wzorce architektoniczne 67 / 78

(68)

Mikrokernel

External Server +receiveRequest() +dispatchRequest() +executeService()

Microkernel +executeMechanism() +initCommunication() +findReceiver() +createHandle() +sendMessage() +callInternalServer()

Internal Server +executeService() +receiveRequest()

Adapter +callService() +createRequest()

Client +doTask() calls

activates

initializes communication

calls service send request

Rysunek 9:Źródło: własne

Wzorce architektoniczne 68 / 78

(69)

Mikrokernel

Microkernel implementuje centralne serwisy takie jak udogodnienia komunikacji, zarządzanie zasobami. Większość części zależnych od sprzętu jest ukrytych przed innymi częściami. Mikrokernel jest odpowiedzialny także za zarządzanie zasobami systemowymi takimi jak procesy, pliki. Kontroluje dostęp do tych zasobów. Mikrokernel implementuje atomiczne serwisy, które będziemy nazywać

mechanizmami. Na podstawie tych mechanizmów konstruowane są bardziej skomplikowane funkcjonalności, zwane działaniami (ang.

policies).

serwer wewnętrzny zwany także podsystemem rozszerza

funkcjonalność dostarczaną przez mikrokernel. Reprezentuje oddzielny komponent oferujący dodatkową funkcjonalność. Mikrokernel

wywołuje funkcjonalność serwerów wewnętrznych przez żądania serwisowe. Zauważmy, że serwery wewnętrzne są dostępne tylko poprzez mikrokernel dla innych komponentów.

Wzorce architektoniczne 69 / 78

(70)

Mikrokernel

serwer zewnętrzny implementuje widok specyficznej dziedziny aplikacji. Każdy serwer zewnętrzny uruchamiany jest jako oddzielny proces. Serwer zewnętrzny otrzymuje żądania serwisowe od aplikacji klienckiej używając do tego udogodnień komunikacji dostarczanych przez mikrokernel, interpretuje te żądania, wykonuje odpowiednie serwisy i zwraca rezultat do klienta.

klient jest aplikacją powiązaną z dokładnie jednym serwerem zewnętrznym

adapter inaczej emulator to interfejs pomiędzy serwerem zewnętrznym a klientem. Używa on mechanizmów komunikacji dostarczanych przez mikrokernel.

(71)

Pozostałe wzorce

Pozostałe wzorce 71 / 78

(72)

Wstrzykiwanie zależności (ang. Dependency Injection, DI)

sterowanie zostaje odwrócone w obszarze tworzeniapowiązań pomiędzy obiektami, czyli powiązania te są kontrolowane poza tymi obiektami

wzorzec ten jest implementowany za pomocą agregacji, podobnie jak wzorzec strategii

DI vs wzorzec strategii: we wzorcu strategii możemy podmieniać strategie w czasie życia obiektu, a w DI zazwyczaj używamy jednej instancji zależności

wyróżniamy 3 typy wstrzykiwania zależności: wstrzykiwanie konstruktora – zależności są dostarczane przez konstruktor, wstrzykiwanie settera – klient posiada metodę ustawiającą, którą wykorzystuje injector do wstrzyknięcia zależności,wstrzykiwanie interfejsu– zależność posiada metodę, która wstrzykuje zależność do klienta podanego do tej metody, klient musi implementować interfejs, który dostarcza metodę settera, która akceptuje zależność.

(73)

Wstrzykiwanie zależności

w przypadku wstrzykiwania interfejsu, asembler pobiera referencję do klienta, przekazuje ją do obiektu zależnego, który przekazuje swoją referencję do klienta

mogą być stosowane różne wzorce konstrukcyjne takie jak budowniczy, fabryka abstrakcyjna itp.

Pozostałe wzorce 73 / 78

(74)

Wstrzykiwanie interfejsu

Assembler (Injector) Dependency (Service)

Client +setService() ServiceSetter

setService()

Rysunek 10:Źródło: własne

Pozostałe wzorce 74 / 78

(75)

Wstrzykiwanie zależności przykład

// An example without dependency injection public class Client {

// Internal reference to the service used by this client private Service service;

// Constructor Client() {

// Specify a specific implementation in the constructor instead of using dependency injection

service = new ServiceExample();

}

// Method within this client that uses the services public String greet() {

return "Hello " + service.getName();

} }

Pozostałe wzorce 75 / 78

(76)

Wstrzykiwanie zależności przykład

// Constructor

Client(Service service) {

// Save the reference to the passed-in service inside this client

this.service = service;

}

// Setter method

public void setService(Service service) {

// Save the reference to the passed-in service inside this client

this.service = service;

}

(77)

Wstrzykiwanie zależności przykład

// Service setter interface.

public interface ServiceSetter {

public void setService(Service service);

}

// Client class

public class Client implements ServiceSetter {

// Internal reference to the service used by this client.

private Service service;

// Set the service that this client is to use.

@Override

public void setService(Service service) { this.service = service;

} }

Pozostałe wzorce 77 / 78

(78)

Wstrzykiwanie zależności przykład

public class Injector {

public static void main(String[] args) { // Build the dependencies first

Service service = new ServiceExample();

// Inject the service, constructor style Client client = new Client(service);

// Use the objects

System.out.println(client.greet());

} }

Cytaty

Powiązane dokumenty

● Jednym z najbardziej podstawowych aspektów wzorców jest to Ŝe opisują one problemy, które były wielokrotnie rozwiązywane przez wiele osób (powtarzają się),

Zaimplementować klasę wizytującą ze zwracaniem napisu zawierącego macierz oraz dodatkowo informację czy jest to macierz kwadratowa czy nie. • Utworzyć interpreter do

[r]

dekorator vs kompozyt: dekorator można traktować jako uproszczony obiekt złożony obejmujący tylko jeden komponent; dekorator dodaje nowe zadania i nie jest przeznaczony do

public class FlipDownCommand implements Command { private Light theLight;{. public FlipDownCommand(Light light) { this.theLight

Z punktu widzenia użytkownika interfejs aplikacji jest niezwykle ważny, a jego dobre zaprojektowanie i funkcjonalność nieraz przesądza o satysfakcji

Wzorzec Adapter konwertuje interfejs jednej klasy na interfejs innej klasy.. Używamy tego wzorca, jeśli chcemy, żeby dwie niezwiązane ze sobą klasy współpracowały ze sobą

chronione metody D oraz klas pochodnych po D. prywatne