Thursday, May 23, 2013

Inversion of Control


 შეიელბა ასე გავმარტოთ. Inversion of Control (IoC) და Dependency Injection (DI) პატერნები არიან ყველანი იმისათვის რომ დეფენდენსები არ გქონდეთ თქვენს კოდზე და არხდებოდეს კოდის განმეორებები.  კოდის ოპტიმიზაცი ყოველთვის პრიორიტირებულია ჩვენთვის. ოპტიმიზაციის მთარავი მიზანიც ის არის რომ კოდი ლამაზად და გასაგებად ეწეროს, და ყველაზე მთავარი რაცაა არ ხდებოდის კოდის ხშირი გამეორებები, როდესაც მცირე რამეა შესაცვლელი.

ერთერთი მაგალითი ასეთი შეიძლება მოვიყვანოთ.

გვაქვს List რაღაც A ტიპის ობიექტებით სავსე და მინდა მისი გადაყვანა Map ში. შემდეგ ვაკეთებ ისევ სიას, ოღონდ B ტიპის ობიექტებით სავსეს და მინდა მისი გადაყვანა კვლავ Map ში. ამ შემთხვევაში შეგვიძლია მხოლოდ ერთი მეთოდი გვქონდეს გადაყვანის, არ ვაკეთოთ ტიპებით overload ები. თუ ასეთი 10 ტიპის ობიექტი მექნება, 10 overload არ გავაკეთებ.

მაგალითად, გვაქვს კლასი წიგნებისა.
/**
* For My Book Library
* @author v.koroghlishvili
*
*/
private static class Book {
private final Long id;
private final String name;
public Book(Long id, String name) {
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
}
view raw gistfile1.java hosted with ❤ by GitHub

შევავსოთ იგი:
List<Book> list = new ArrayList<Book>();
list.add(new Book(1L, "Just Spring"));
list.add(new Book(2L, "EJB 3.1"));
list.add(new Book(3L, "Node.JS"));
view raw gistfile1.java hosted with ❤ by GitHub

ახლა დაგვჭირდება ერთი ინტერფეისი, რომელშიც მეთოდის პროტოტიპს ჩავწერთ – მეფითა keyს ამოღებისა. მთავარი პრობლემა ჩვენ ის გვაქვს რომ არ ვიცით ობიექტის key რა იყოს (ზოგ შემთხვევაში რა არის, ზოგში რა). ამიტომ თითოეული ობიექტისათვის გავაკეთოთ კლასი, რომელიც იმპლემენტაციას გაუკეთებს KeyFinder–ს.

მაგალითად ინტერფეისი:
public static interface KeyFinder<K, E> {
K getKey(E e);
}
view raw gistfile1.java hosted with ❤ by GitHub


და ჩვენი წიგნებისთვის გვექნება იმპლემენტაცია შემდეგნაირი, თუ Id გვინდა იყოს მეფსი key.

private static class BookKeyFinder implements KeyFinder<Long, Book> {
@Override
public Long getKey(Book e) {
return e.getId();
}
}
view raw gistfile1.java hosted with ❤ by GitHub

და გვექნება მხოლოდ ერთი მეთოდი, ზოგადი. რომელსაც გადაეცემა სია ნებსმიერი ტიპისა. და ინტერფეისი რომ გავაკეთეთ KeyFinder, აქაც განზოგადებული ტიპებით. მოხდება Mapის შექმნა. შემდეგ გადავუვლით ყველა ელემენტს სიაში, და
სათითაოდ ამოვიღებთ გასაღებს,
public static <K, E> Map<K, E> listToMap(List<E> list, KeyFinder<K, E> finder) {
Map<K, E> mp = new HashMap<K, E>();
for (E e : list) {
K key = finder.getKey(e);
mp.put(key, e);
}
return mp;
}
view raw gistfile1.java hosted with ❤ by GitHub

კოდს თუ დააკვირდებით ,  KeyFinder   finder გვაქვს, სადაც  KeyFinder ინტერფეისი არის.  resolver აქვს რეფერენსი რომელიმე კლასის ობიექტთან , რომელსიც აკეთებს ინტერფეისი იმპლემენტაციას ––> მას აქვს Overriden მეთოდი გასაღების ამოღებისა ––> მისი დახმარებით , სწორედ ამ ტიპის კლასის ობიექტიდან როგორ ამოვიღოთ გასაღები ვიცით.

თუ დავამატებთ მაგალითად მანქანების კლას. დაგვჭირდება უბრალოდ   CarKeyFinder -ის დაწერა რომელიც იმპლემენტაციას გაუკეთებს KeyFinder-ს. ან მეორე ვარიანტი ისაა რომ პირადპირ მანქანის კლასმა გაუკეთოს იმპლემენტაცია KeyFinder–ს და ცალკე არ გავიტანოთ - ნუ, გემოვნების ამბებია.




MVN Manifest Entries

თუ აღმოჩნდა რომ manifest ფაილის კონფოგურაციისათვის Maven–ის სტანდარტული პარამეტრები არ გყოფნით, იმისათვის რომ manifest თგვენს გემოზე ააწყოთ (თქვენი საკუთარი ველები დაუმატოთ), ამისთვის მავენს აქვს <manifestEntries>  ტეგი.  გამოყენება მარტივია:
<manifestEntries>
      <YOURTAG> value </YOURTAG>
</manifestEntries>

იხილეთ მაგალითაი:
<build>
<finalName>${artifactId}-${version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>false</addClasspath>
<classpathPrefix>dependency/</classpathPrefix>
</manifest>
<manifestEntries>
<Trusted-Library>true</Trusted-Library>
<URL>${project.url}</URL>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jarsigner-plugin</artifactId>
</plugin>
</plugins>
</build>
view raw gistfile1.xml hosted with ❤ by GitHub

შედეგი კი გვენქება დაახლოებით ასეთი.
Manifest-Version: 1.0
Trusted-Library: true
URL: vakhokor.blogspot.com
Build-Jdk: 1.7.0_21
Built-By: v.koroghlishvili
Created-By: Apache Maven
Archiver-Version: Plexus Archiver
view raw gistfile1.txt hosted with ❤ by GitHub

Monday, May 20, 2013

Strategy Pattern

Stragegy patern.   ასევე ლიტერატურაში შეიძლება შეგხვდეს მისი სახელწოდეა როგორც  Policy pattern. მისი საშვალებით ალგორითმის ქცევის არჩევა ძალზედ მარტივად ხდება. იმას, თუ რომელი ალგორითმი იქნება გამოყენებული, კლიენტი განსაზღვრავს.

 დამავწყდა მეთქვა, რომ, ეს დიზაინ პატერნი Creational pattern ოჯხს განეკუთნება.

ამ დიზაინ პატერნის სტრუქტურა ასეთია:




როგორც სურათზე ხედავთ, გვაქვს სტრატეგიის ინტერფეისი, რომელთა მრავალი იმპლემენტაცია შეილება გვქონდეს–  მაგალითად გვინდა Payment ის შესრულება. იგი შეიძლება შესრულდეს Visa ელექტრონით, შეიძლება MasterCard -ით.

ალგორითმი უსმენს კლიენტს და იმ იმპლემენტაციას უშვებს რომელიც მოთხოვნას შეესაბამება. მოსმენას და შესაბამის სტრატეგის ალგორითმის გამოძახებას Context  ემსახურება.

დავიწყოთ მაგალითის წერა, და  თან განვმარტოთ. თავდაპირველად, გადახდისთვის გავაკეთოთ enum, რომლებითაც იქნება შესაძლებელი გადახდა.
/**
* @author v.koroghlishvili
* Enum for Payment methods
*/
public enum PaymentType {
VISA_ELECTRON, MASTERCARD
}
view raw gistfile1.java hosted with ❤ by GitHub
შემდეგ ამ ენამიდან რომელიმეს Context–ს გადავცემთ.  თუ სხვა ჯერზე ფეიმენთის გაკეთება  გადახდის სხვა ტიპით მომინდება, უბრალოდ  კონტექტს ვეტყვი ამ ყოველივეს.



/**
*
* @author v.koroghlishvili
*
*/
public class PaymentContext {
private PaymentRule paymentRule;
public PaymentContext(PaymentType setting) {
this.paymentRule = createRule(setting);
}
/**
* This method chooses payment method,
* using payment type
* @param setting
* @return
*/
private PaymentRule createRule(PaymentType setting) {
switch (setting) {
case MASTERCARD:
return new VisaElectronRule();
case VISA_ELECTRON:
return new MaserCardRule();
default:
return null;
}
}
public void cheeckOut(String number) {
paymentRule.makePayment(number);
}
public PaymentRule getValidationRule() {
return paymentRule;
}
}
view raw gistfile1.java hosted with ❤ by GitHub
PaymentContext, რომელიც განსაზღვრავს რომელი implement გაუშვას. აქ მარტივადაა ყველაფერი, switch ით ვნსაზღვრავ საჭიროს. როდესაც კონტესტის ობიექტს შევქმნი, კონსტრუქტორშივე ვახდენ შესაბამისი მეთოდის მინიჭებას.


PaymentRule ინტეფეისი ,რომლის შვილებიც იქნებიან კონკრეტული იმპლემენტაციები. ჩვენს შემთვევაში ერთი მასტერქარდთან მომუშავე, მეორე ვიზა ელექტრონთან. სწორედ კონტექსტში  PaymentRule  შვილის რომელიმე ობიექტს ვქმნი (switch ებში), და ვანიჭებ paymentRuleს, რომელიც არის PaymentRule   ტიპისა.


ახლა დავწეროთ კონკრეტული სტრატეგიის იმპლემენტაციები.

ეს VisaElectron იმპლემენტაცია.  ეს კი უკვე MasterCard–ის:


საბოლოოდ კი ყველაფერი ძალიან მარტივი გვაქ.