22 Ocak 2017 Pazar

GoF - Proxy Örüntüsü

Proxy - Yapısal Örüntü
Proxy bir yapısal örüntüdür. Amacı gerçek nesneye erişimi saklamak/engellemek/kontrol etmek.

Java
Proxy Sınıfı bu örüntüyü gerçekleştiriyor sayılabilir.

Bileşenleri
Açıklaması şöyle
Proxy Design Pattern uses three components to implement:
- Subject - the interface which exposes the functionality.
- Real Subject - the class implements the Subject and provides the concrete implementation of the interface. In this class, we hide behind the Proxy.
- Proxy - the class implements the Subject so that it can substitute Real Subject objects. It maintains the reference of the Real Subject to the substituted Proxy object so that it can forward a request to the Real Subject whenever needed.
Bazı Proxy Türleri
Açıklaması şöyle
We can do proxy in many ways like:
- Virtual Proxy - Do lazy loading of memory rich or heavy objects until it is needed.
- Decorative Proxy - Add extra functionality to the existing objects just like we do in Decorator Design Pattern. 
- Protective Proxy - Control access to the objects functionality.
- Debugging Proxy - Add logs that may also be helpful in debugging.
- Remote Proxy - provides a local representative for a remote object like stub objects in RMI/RPC or CORBA.
- Smart Proxy - checking the lock on real object while updating, loading persistence object upon the first reference, managing real object reference, etc.
Proxy ve Decorator Örüntüleri
Proxy ve Decorator birbirlerine çok benziyorlar. Ancak Decorator nesneye yeni davranış ekler. Proxy ise gerçek nesneye erişimi kontrol eder. Decorator ve Proxy arasındaki önemli bir farkın açıklaması şöyle
The difference between Proxy and Decorator according to the GoF is that Proxy restricts the client. Decorator does not. Proxy may restrict what a client does by controlling access to functionality; or it may restrict what a client knows by performing actions that are invisible and unknown to the client. Decorator does the opposite: it enhances what its delegate does in a way that is visible to clients.

Virtual Proxy
Bence Proxy örüntüsünün en önemli faydası yaratması pahalı olan nesnelerin son ana kadar yaratılmasını engellemek yani lazy davranmak

Protective Proxy
Gerçek nesneye erişimi güvenlik sebebiyle engeller, araya girer.

Kullanım
Örnek - Virtual Proxy
Şöyle yaparız. Bu kodun niçin Proxy olduğunun açıklaması şöyle
A Decorator is always passed its delegatee. A Proxy might create it himself, or he might have it injected.
Burada ProxyImage logic içeriyor ve kendisine verilen parametreye bakarak doğru sınıfı yani diskten yüklenen RealImage veya uzaktan yüklenen RemoteImage sınıfını lazy olarak yaratıyor.
public interface Image {
  ...
}

public class RealImage implements Image {
 ...
}

public class RemoteImage implements Image {
 ...
}

public class ProxyImage implements Image {
  private Image image;  
  protected String remoteHost;
  protected String fileNameWithPath;

  public void load() {
    if (remoteHost != null) {
      image = new RemoteImage(remoteHost, fileNameWithPath);
    } else {
      image = new RealImage(fileNameWithPath);
    }
  }
  ...
}
Örnek - Decorative Proxy
Şöyle yaparız.
public class Subject
{
  public virtual void Foo ()
  {
    ...
  }
}

public class SubjectProxy : Subject
{
  public override void Foo()
  {
    ...
  }
}
Şöyle kullanırız.
public Subject GetSubject()
{
    return new SubjectProxy();
}

Subject subject = GetSubject();
subject.Foo(); // would use the proxied method

19 Ocak 2017 Perşembe

AdjustTokenPrivileges

Şöyle yaparız.
bool EnableShutdownPrivilege() {

  HANDLE hProcess = NULL;
  HANDLE hToken = NULL;
  LUID uID = { 0 };
  TOKEN_PRIVILEGES stToken_Privileges = { 0 };

  hProcess = ::GetCurrentProcess();

  if (!::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken))
    return false;

  if (!::LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &uID))
    return false;

  stToken_Privileges.PrivilegeCount = 1;
  stToken_Privileges.Privileges[0].Luid = uID;
  stToken_Privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

  if (!::AdjustTokenPrivileges(hToken, false,
    &stToken_Privileges, sizeof(stToken_Privileges), NULL, NULL))
    return false;

  if (::GetLastError() != ERROR_SUCCESS)
    return false;

  ::CloseHandle(hToken);
  return true;
}


13 Ocak 2017 Cuma

Gömülü Proje - Fixed Rate Timer

Giriş
Amacımız belli bir süreden önce (örneğin 30 saniye) yenilenmesi gereken nesneleri yönetmek. Eğer belirtilen süre içinde yenilenmezse o nesne için kurulan TimerHandler nesne için belirtilen TimerKey ile çağrılır. Eğer nesne yenilenirse timer bir kere daha 30 saniye sonrasına kurulur.

FixedRateTimerManager nesnesi Component veya Manager içinde yaşar. Bu nesneler ana thread tarafından çalıştırılır. Böylece timer nesnesi de sürülmüş olur.
Main Thread-->Component -->Manager -->FixedRateTimerManager

Tasarım
TimerKey, ITimerHandler, FixedRateTimer, FixedRateTimerManager sınıflarından oluşur.

TimerKey
3 tane unsigned int alan bir yapı olsun. Bu yapı tasarımdaki önemli noktalardan birisi.

Bazı tasarımlarda, timer key alanı olmadan çalışır. Örneğin amaç 30 saniyede bir liste üzerinde yürümektir. Bu amaç için key alanı saklamak gerekmez.

Bazı tasarımlarda, her timer nesnesinin bir ID alanı vardır. Timer tetiklenince ID bilgisini de verir. Kod yazan kişi ID üzerinden haricen yönettiği state bilgisine erişir ve bir işlem yapar. Ancak bu da zor bir tasarım çünkü timer ile haricen tutulan "map" veri yapısını birlikte yönetmek gerekir.

Benim seçtiğim yöntemde timer tetiklenirken state bilgisini de sağlıyor. Böylece her şey daha kolay bir hale geliyor. State her zaman int tipi olduğu için sorun olmadı.

Bir diğer yöntem ise state bilgisini handler içinde saklamak. Handler yaşam döngüsü heap üzerinde olabilir. Timer bitince handler da silinebilir. Ancak gömülü ortamda malloc/new yapmamak için bu yöntemi seçmedim.

ITimerHandler
ITimerHandler isimli bir arayüzümüz olsun. Bu arayüzün TimerKey nesnesi alan OnTimeOut metodu olsun.
void OnTimeOut (TimerKey& key);

FixedRateTimer
Intrusive bir yapı. pNextTimer, pPrevTimer,isPeriodic,ExpirationTime,isActive alanları olsun.

FixedRateTimerManager
FixedRateTimerManager isimli bir sınıfımız olsun. Bu sınıf tüm FixedRateTimer nesnelerini iki veri yapısı kullanarak yönetsin.

İlk yapı bir "double linked list" olsun. Bu yapı nesneleri absolute timeout zamanına göre sıralı saklasın. Yani bitme zamanı en yakın olan nesne en başta,  bitme zamanı en uzak olan nesne ise en sonda olsun. Absolute time kullanabilmek için sistemde sürekli artan bir monotonic zaman kaynağı olması yeterli.

İkinci yapı ise bir "hashmap" olsun. Belirtilen TimerKey değerine sahip TimerHandler nesnesi silinebilsin, tekrar kurulabilsin.

FixedRateTimerManager belirtilen bir TimerKey nesnesi için bir TimerHandler eklerken her iki yapıyı da kullansın.

FixedRateTimerManager yönettiği belli bir TimerKey için yeniden kurma imkanı sağlasın. Yeniden kurulan timer listenin en sonuna taşınır. Aslında burası en kritik nokta. Tüm nesnelerin aynı timeout süresini kullandığını bildiğim için liste içinde dolaşarak timer nesnesini doğru yere yerleştirmekle uğraşmıyorum. Yani liste kendiliğinden sıralı oluyor.
Elimdeki liste şöyle olsun
A (30) , B (60) , C (60)
Şu anki saat ise 30 olsun. A nesnesi tekrar kurulunca liste şöyle olur.
B (60), C (60), A (90)

FixedRateTimerManager (TimeSpan& rate);
Kullanılacak sabit süre belirtilir.

void RunTimers () metodu çağrılınca liste dolaşılır.  Biten FixedRateTimer nesnesi tetiklenir. Eğer nesne periyodik ise bir sonraki tetiklenme zamanı aranir ve listenin en sonuna taşınır. Eğer nesne "single shot" ise listeden silinir.

bool StopTimer (TimerKey & key);
Belirtilen anahtar değerine sahip timer listeden silinir.

bool StartOrRescheduleTimer (TimerKey & key, ITimerHandler* pHandler);
Eğer belirtilen timer yoksa yeni bir timer başlatılır. Varsa 30 saniye sonrası için tekrar kurulur.


GoF - Command Örüntüsü

Command - Davranışsal Örüntü
Bu örüntünün benim gördüğüm iki kullanım şekli var.

1.Virtual Metod Şeklinde Birleştirilemeyen Farklı Nesneleri Bir Arada Kullanmak
Dispatch table aynı imzayı taşıyan virtual metodları gerçekleştirmek için kullanılıyor. Command Pattern bir çeşit dispatch table gibi düşünülebilir. Aradaki en önemli fark Command örüntüsü ile aynı imzanın kullanılmak zorunluluğunun ortadan kalkması. Yani farklı arayüzler sunan nesneleri bir arada kullanmak için bu örüntü ideal.

2.Aynı Nesne İçindeki If/Else'lerin Kaldırılması
Aşağıdaki gibi if/else veya switch/case'ler içeren metodlar  varsa bu örüntü kullanılabilir.
public void somethingHappened(int message){
  if(message == AN_INT_VALUE) doSomething();
  if(message == ANOTHER_INT_VALUE) doSomeThingElse();
  if(message == A_DIFFERENT_INT_VALUE) doAnotherThing();
}
Kim (Who) ve Ne Zaman(When) Soruları
İyi bir command örüntüsünde command nesnesi kim ve ne zaman sorularıyla ilgilenmez. Dolayısıyla command örüntüsü içinde popup kutuları çıkartmak gibi fikirler iyi şeyler değildir.

Klasik Örnek
Command örüntüsü için verilen klasik örnek, bir çok farklı modeldeki cihazı aynı arayüz ile kumanda edebilmek.

Command ve Event Arasındaki Fark
Command ve Event birbirlerine çok benzerler. Aralarında küçük bir fark bulunur. Anlamsal olarak Command bir cevap bekler

Örnek
Örneğin ShipOrder bir command olarak kabul edilirse bu emri gönderen başarılı veya başarısız oldu diye bir cevap bekler.

Event ise bir olay hakkında bilgi verdiği için cevap beklemez. Örneğin OrderShipped şeklinde bir event bilgilendirme amaçlıdır.

Örnek
Örneğin MakeTea bir command kabul edilirse bu emrin sonucunda NewTea gibi bir cevap gelmesi gerekir. Bunu takiben TeaMade şeklinde bir event'in yayınlanması gerekir.

Komutun Sonucunu Almak
Komutun sonucunu almak için ortak bir arayüz, data transfer object gibi bir şey kullanmak gerekiyor.
Eğer sonuç beklenmiyorsa şöyle kullanılabilir.
public abstract class Command {
  public abstract void execute();
}
Bazen Command'in çalışması sonucunda bir event üretilir. Bu durumda da event'leri ve command'leri işleyen ayrı bir katman gerekebilir. Bu katmana Prevalence Layer deniliyor. Bu katman önce bir önceki command'lerin çıktısı olan event'leri işler daha sonra da yeni command'leri işler şeklinde bir mantık kullanıyor.

Command ve Producer/Consumer
Command örüntüsü ile Producer/Consumer örüntüsü çok rahat birleştirilebilir.

Bir projede şöyle bir yapı kurduk.
1. Component 1
Ağdan yakalanan paketleri süz. Diğer bileşene ver.
Component1 ->Command Queue ->Component2
2. Component 2
Gelen paketleri sıkıştır ve kuyrukta sakla. Context modelleri saklayan yönetici sınıf.
Component2 ->Command Queue ->Context ->Models
Bu örnekte Component nesnesleri Active Object gibi davranıyor.  Gerekirse Active Object iki farklı kaynaktan beslenebilir.

Command ve Active Object
Active Object bir metod çağrısının başka bir thread içinde yerine getirilmesi demek. Command örüntüsü Active Object ile birleştirilebilir. Çok basit bir örnek şöyle. Önce klasik Command hiyerarşisi tanımlanır.
struct Command {
  virtual ~Command() {}
  virtual void exec() = 0;
}
class CopyCommand : public Command {
  const QString from, to;
  CopyCommand( const QString & from, const QString & to )
            : Command(), from( from ), to( to ) {} 
  void exec() { QFile::copy( from, to ); }
};
class MoveCommand : public Command {
        // ...
};
Sonra içinde thread ve kuyruk barındıran bir sınıf tanımlanır. Sınıfın copy ve move metodları birer command nesnesini kuyruğa eklerler. Kuyruğu boşaltan tek thread mesajları işler.
class MyActiveObject : public QObject {
    Q_OBJECT
public:
    explicit MyActiveObject( QObject * parent=0 )
        : QObject( parent ),
          thread(),
          queue(),
          mutex(),
          queueNotEmpty() {
        thead.start();
    }
    ~MyActiveObject() {
        // shut down thread:
        enqueue( 0 ); // end marker
        thread.wait(); // join with worker thread
    }
private:
    void enqueue( Command * cmd ) {
        const QMutexLocker locker( &mutex );
        queue.enqueue( cmd );
        queueNotEmpty.wakeOne();
    }
   void run() {
        while ( true ) {
            QMutexLocker locker( &mutex );
            while ( queue.isEmpty() )
                queueNotEmpty.wait( &mutex );
            Command * cmd = queue.dequeue();
            locker.unlock():
            if ( !cmd ) return; // end marker
            cmd->exec();
            delete cmd;
        }
    }
private:
    QThread thread;
    QQueue<Command*> queue;
    QMutex mutex; // protects 'queue'
    QWaitCondition queueNotEmpty;
};
Sınıfın metodları şöyledir.
public Q_SLOTS:
    void copy( const QString & from, const QString & to ) {
        enqueue( new CopyCommand( from, to ) );
    }
    void move( const QString & from, const QString & to ) {
        enqueue( new MoveCommand( from, to ) );
    }
Periyodik Yani Tick'lenen Active Object
Bazı projelerde Active Object nesnesinin her zaman çalışması istenmez. Bu nesne periyodik olarak - örneğin 1 saniye de bir - uyanır kuyrukta bekleyen işleri çalıştırır ve tekrar uyur.

Command ve History
Command tarihçesi için şöyle yaparız.
class CommandSession {
  private List<Command> commands = new ArrayList<>();
  private ListIterator<Command> scroller;

  public void execute(Command command) {
    scroller = null;
    commands.add(command);
    command.execute();
  }

  public Command scrollUp() {
    if (scroller == null) {
      scroller = commands.listIterator(commands.size());
    }
    if (scroller.hasPrevious()) {
      return scroller.previous();
    }
    return null;
  }
}