Java Template Design Pattern

Mustafa Sipahi
Tapu.com Bakış Açısı
4 min readMar 17, 2022

Dinamik ve sub classlar tarafından değiştirilebilir algoritmalar oluşturmak için template tasarım şablonu kullanılır. Bazı durumlarda ihtiyaçlarımıza göre abstract bir base class tanımlaması yaparak, bu class ı extends eden sub classlar ile yazılım geliştirmesi yapılmaktadır. Ancak buradaki sub class ların her durumda base class da yer alan tüm methodları implemente etmesini istemediğimiz durumlar olmaktadır.

Template Design Pattern bu mantık ile çalışan bir tasarım desenidir. Daha çok sıralı operasyonları içeren algoritmalar için kullanılmaktadır. Bu sıralı algoritmada bazı fonksiyonların belirli durumlarda farklı davranışlar sergilemesini bekleyebiliriz. Farklı davranışlar sergileyecek olan bu fonksiyonlar base class dan extend ettikleri class içerisinde tanımlanmaktadır. Bu tanımlamalar ile base class sub classlar yardımıyla kolayca genişletilerek, sahip oldukları kod parçalarının yeniden kullanılabilirliği arttırılmaktadır.(Code Reusability)

Base class içerisinde tanımlanmış olan diğer fonksiyonlarda aslında standart olarak hep aynı işi yapmaktadırlar.

Böylece hem kod tekrarının önüne geçilerek kodun tekrar kullanılabilirliği arttırılmış hem de algoritma iskeletinde yapılacak bir düzenlemenin tek bir yerden yapılması sağlanmış olmaktadır.

Örnek olarak bir veritabanı bağlantısını düşünebiliriz. Kullanıcının veritabanına CRUD işlemlerinden herhangi birini kullanmak istemesi durumunda, bir bağlantı açmak istemesi gerekecek, gerekli sorgusunu çalıştırdıktan sonra veritabanı bağlantısını kapatması gerekecektir. Her sorguda aynı şekilde çalışan bir bağlantı açma ve kapatma senaryosu ile birlikte, ihtiyaca göre farklılık gösteren gerekli sorgu senaryosu çalışmaktadır. Burada bağlantı açma ve kapatma işlemleri bir template üzerinden yapılarak, sorgular gerekli sub classlar ile özelleştirilebilmektedir.

Örnek Senaryo :

Bir sms gönderme işlemi düşünelim. Sahip olduğumuz veritabanında kullanıcıların Adı, Soyadı ve telefon numaraları bulunmaktadır. Bu kullanıcalara farklı senaryolarda farklı smsler göndermek istemekteyiz. Gönderilecek olan smsler farklı parametreler içermektedir. Gönderdiğimiz smslerin log kaydını tutmak için de hangi kullanıcıya hangi sms in gönderildiğini kaydetmek istiyoruz.

Senaryomuzda template içerisinde kullanıcının veritabanından bulunması, gerekli ad, soyad ve telefon numarası bilgilerinin alınması ve log kaydının yapılması işlemleri ortak ve aynı algoritmaya sahip oldukları için template içerisinde yapılacaktır. Ancak ilgili smsler farklı parametreler içerdikleri için sub classlarda implemente edilerek sms gönderimi yapılacaktır.

UML Class Diagramın da görüldüğü gibi sms göndermemizi sağlayan bir api kullanılacaktır. Bu api ye gelen smsType ile execute methodu çalıştırılacaktır. Execute eden ilgili “smsType” öncelikle template içerisinde kullanıcıyı ve bu kullanıcının detayını veritabanında bulacaktır. Abstract olan sendSms methodu ile base classı extend eden ve içerisinde bu methodu implemente eden classlar ile sms gönderilecek, gönderilen smsi string olarak geri dönecektir. Template içerisinde yer alan log methodu ile gönderilen sms kaydedilecektir.

@RestController
public class SmsApi {
@PostMapping(value = "/send-sms")
public void sendSms(@RequestBody SmsDto dto) {
dto.getSmsType().getClazz().execute(dto);
}
}

sendSms() methoduna gönderilecek olan dto içerisinde, istenilen smsType yer almaktadır. Bu smsType ile SendSmsTemplate içerisinde yer alan execute() methodu çağrılmış olacaktır.

Adım Adım SmsApi :

  1. Gönderilmek istenen sms “/send-sms” endpointi ile tetiklenmektedir.
  2. Bu endpoint SmsDto objesi almakta ve bu obje içerisinde “customerId” ve “smsType” değişkenleri yer alması gerekmektedir.
  3. Bu dto içerisinde ilgili “smsType” değişkeni ile “getClazz()” methodu çağrılarak “SmsFactory” içerisinde yer alan ilgili service class ına ulaşılmış olunacaktır.
  4. “SmsFactory” class ında yer alan servislerin extend ettiği base class da yer alan “execute(dto)” methodu çağrılacaktır.
public enum SmsFactory {Sms1(Sms1Service.class),
Sms2(Sms2Service.class),
Sms3(Sms3Service.class);
private final Class<? extends SendSmsTemplate> clazz;

SmsFactory(Class<? extends SendSmsTemplate> clazz) {
this.clazz = clazz;
}

public Class<? extends SendSmsTemplate> getClazz() {
return clazz;
}
}

SmsApi de kullanılacak smsType ların hangi servis ile çalışacağını belirttik. Buradaki servisler base classı extend eden sub classlar olacaktır. Bu sub class larda sadece farklılaşacak olan sms gönderme işlemi yapılacaktır.

Adım Adım SmsFactory :

  1. SmsFactory class ında yer alan ve ilgili enum tipine göre farklılaşarak çağrılması istenen service ler yer almaktadır (Sms1Service, Sms2Service, Sms3Service).
  2. Bu servislere ilgili enum tipinin “getClazz()” methodu çağrılarak ulaşılmaktadır.
public abstract class SendSmsTemplate {  private CustomerService customerService;
protected SmsService smsService;
private LogService logService;
public void execute(SmsDto dto) {
Customer customer = customerService.findCustomer(customerId);
String smsText = sendSms(dto, customer);
logService.save(smsText, customer);
}
protected abstract String sendSms(SmsDto dto, Customer customer);
}

SmsApi den gelen smsType ile buradaki execute() methodu çalışmaya başlayacaktır.

Adım Adım SendSmsTemplate :

  1. İlk olarak dto içerisinden gelen customerId ile ilgili kullanıcı ve bilgileri veritabanından bulunacaktır.
  2. Daha sonra dto içerisinde gelen smsType ile SendSmsTemplate den extends eden ilgili servis çağrılacak ve ve burada abstract olarak tanımlanmış olan “sendSms” methodu çağrılacaktır.
  3. İlgili servis ile çağrılan “sendSms” methodu farklılaşan parametreler ile sms gönderimi yapacaktır.
  4. Son olarak gönderilen smsin ve kime gönderildiğinin log kaydı tutulacaktır.
@Service
public class Sms1Service extends SendSmsTemplate {
@Override
protected String sendSms(SmsDto dto, Customer customer) {
//Other Differences
return smsService.sendSms(sms1Parameter, customer);
}
}

Sms1Service

@Service
public class Sms2Service extends SendSmsTemplate {
@Override
protected String sendSms(SmsDto dto, Customer customer) {
//Other Differences
return smsService.sendSms(sms2Parameter, customer);
}
}

Sms2Service

@Service
public class Sms3Service extends SendSmsTemplate {
@Override
protected String sendSms(SmsDto dto, Customer customer) {
//Other Differences
return smsService.sendSms(sms3Parameter, customer);
}
}

Sms3Service

Yukarıdaki base class dan extend eden servis classları ile farklılaşan sms ler gerekli parametreleri kullanılarak ilgili kullanıcılara gönderilecektir.

Kısaca ifade etmek gerekirse, template içerisindeki execute() methodu algoritma, servisler içerisinde yeralan abstract sendSms() metodu ise algoritma adımıdır.

Template Design Pattern Kullanmasaydık:

Bu algoritmada template tasarım şablonu kullanmamış olsaydık, tüm sms gönderimleri için birbirini tekrar eden kullanıcıları ve detaylarını bulma işlemleri ve log kayıt etme işlemlerini tekrar tekrar yazmamız gerekecekti. Template tasarımı ile hem tekrardan kurtulmuş olduk hem de kod kalitemizi arttırmış olduk.

public enum SendSms {

SMS1 {
Customer customer = customerService.findCustomer();
String smsText = smsService.sendSms(sms1Parameter,customer);
logService.save(smsText, customer);
},

SMS2 {
Customer customer = customerService.findCustomer();
String smsText = smsService.sendSms(sms2Parameter,customer);
logService.save(smsText, customer);
},
SMS3 {
Customer customer = customerService.findCustomer();
String smsText = smsService.sendSms(sms3Parameter,customer);
logService.save(smsText, customer);
}
}

Yukarıda da görüldüğü gibi; her sms tipi için birbirini tekrar eden customer bilgileri veritabanından bulunmakta, tekrarlı sms gönderme methodları ile smsler gönderilmekte ve yine log kayıtları aynı tekrardan geçerek yapılmaktadır.

--

--

Tapu.com Bakış Açısı
Tapu.com Bakış Açısı

Published in Tapu.com Bakış Açısı

Teknoloji, gayrimenkul pazarını çok hızlı değiştiriyor. Biz elimizden geldiğince önden gitmeye çalışıyoruz ve gördüklerimizi paylaşıyoruz.