Kendi denetleyicisini neyin alması gerektiği nasıl belirlenir?


10

PHP ile oluşturulan benim web uygulamasında MVC desen kullanıyorum.

Her zaman bir dizi eylem için yeni bir özel denetleyiciye ihtiyacım olup olmadığını veya var olan bir denetleyiciye yerleştirmem gerekip gerekmediğini belirlemek için uğraşıyorum.

Denetleyiciler oluştururken uyulması gereken iyi kurallar var mı?

Örneğin:

AuthenticationController eylemlerle:

  • index() giriş formunu görüntülemek için.
  • submit() form gönderimi.
  • logout(), açıklayıcı.

VEYA

LoginController eylemlerle:

  • index() giriş formunu görüntülemek için.
  • submit() form gönderimi.

LogoutController eylem ile:

  • index() oturumu kapatmak için.

VEYA

AccountController eylemlerle:

  • loginGet() giriş formunu görüntülemek için.
  • loginPost() giriş formunun gönderilmesi.
  • logoutGet() oturumu kapatmak için.
  • registerGet() kayıt formunu görüntülemek için.
  • registerPost() form gönderimi.

    Ve bir hesapla ilgili diğer tüm eylemler.


Belki RESTful tasarıma bir göz atın. Bu tür her bir sorunu çözmez, ancak bunun hakkında nasıl düşüneceğiniz konusunda size çok iyi bir yön verir.
thorsten müller

Yanıtlar:


3

Kontrolörler için doğru gruplamayı bulmak için testi düşünün .

(Gerçekte herhangi bir test yapmasanız bile, denetleyicilerinizi test etmeye nasıl gideceğinizi düşünmek, bunları nasıl yapılandıracağınız konusunda bazı iyi bilgiler verecektir.)

An AuthenticationController, tek başına test edilemez, çünkü yalnızca giriş ve çıkış yapmak için işlevsellik içerir, ancak başarılı bir giriş yapmayı test edebilmek için test kodunuzun bir şekilde test amaçlı sahte hesaplar oluşturması gerekir. Test altındaki alt sistemi atlayabilir ve test hesaplarının oluşturulması için doğrudan modelinize gidebilirsiniz, ancak daha sonra ellerinizde kırılgan bir testiniz olacaktır: model değişirse, sadece hangi testleri kodlamak zorunda kalmazsınız denetleyicinin arayüzü ve davranışı değişmeden kalmasına rağmen, denetleyiciyi test eden kodu da kodlar. Bu mantıksız.

A LoginController, aynı nedenlerle uygun değildir: önce hesap oluşturmadan test edemezsiniz ve örneğin yinelenen girişleri önlemek, ancak daha sonra bir kullanıcının oturumu kapattıktan sonra oturum açmasına izin vermek gibi test edemeyeceğiniz daha da fazla şey vardır. (Bu denetleyicide oturumu kapatma işlevi olmadığından.)

Bir AccountControllertestinizi yapmak için ihtiyacınız olan her şeyi verecektir: bir test hesabı oluşturabilir ve daha sonra giriş yapmayı deneyebilir, hesabı silebilir ve daha fazla giriş yapamayacağınızdan emin olabilirsiniz, şifreyi değiştirebilir ve giriş yapmak için doğru şifre kullanılmalıdır.

Sonuç olarak: en küçük test paketini bile yazabilmek için, AccountControllermevcut olan tüm işlevselliği yapmanız gerekir. Daha küçük kontrolörlere alt bölümlere ayırmak, uygun bir test için yetersiz işlevselliğe sahip özürlü kontrolörlere sahip gibi görünmektedir. Bu, işlevselliğinin AccountControlleranlamlı olan en küçük alt bölüm olduğuna dair çok iyi bir göstergedir .

Ve genel olarak konuşursak, "testi düşün" yaklaşımı sadece bu senaryoda değil, gelecekte karşılaşacağınız benzer senaryolarda da işe yarayacaktır.


1

Cevap o kadar açık değil

Herhangi bir cevaplama ifadesi yapmadan önce lütfen birkaç şeyi açıklığa kavuşturmama izin verin. Her şeyden önce:

Kontrolör nedir?

Denetleyici, gönderildikten sonra isteği kontrol eden sistemin bir parçasıdır . Böylece, bunu neyle ilgili bazı eylemler olarak tanımlayabiliriz ?

Kontrolörün kapsamı nedir?

Ve bu herhangi bir cevabımızın ne zaman olacağı. Ne düşünüyorsun? Bir şeylerin denetleyicisi mi (örneğin bir Hesap) mı yoksa eylemlerin denetleyicisi mi? Tabii ki, bazı modellerin kontrolörü veya üzerinde eylemler sağlayan daha soyut bir şey.

Cevap...

Eylemleri olan AuthenticationController:

  • giriş formunu görüntülemek için index () işlevini kullanın.
  • Form gönderimini işlemek için boyun eğme ().
  • çıkış (), açıklayıcı.

Hayır, kimlik doğrulama bir süreçtir. Böyle gitme.

Eylemlerle LoginController:

  • giriş formunu görüntülemek için index () işlevini kullanın.
  • Form gönderimini işlemek için boyun eğme ().

Burada aynı. Giriş - eylem. Eylem denetleyicisi oluşturmamanız daha iyi (bununla ilişkili bir modeliniz yok).

Eylemleri olan AccountController:

  • login formunu görüntülemek için loginGet () işlevini kullanın.
  • loginPost () ile giriş formu gönderilir.
  • Oturumu kapatmak için logoutGet () yöntemini kullanın.
  • registerGet () kayıt formunu görüntülemek için.
  • form gönderimini işlemek için registerPost () yöntemi.

Oldukça iyi, ama ben düşük seviyeli denetleyici (denetleyici soyutlama kendisi) bina getirmeye değer olduğuna ikna değilim. Her neyse, * Get veya * Post ile yöntemler oluşturmak belirsizdir.

Herhangi bir öneri?

Evet, düşünün:

AccountController:

  • giriş (AccountModel)
  • çıkış (AccountModel)
  • kayıt (AccountModel)
  • indeksi ()

Ve ilgili model, ofc Hesap sınıfı. Model denetleyici çiftinizi başka bir yere taşıma (gerekirse) ve net bir kod yapma ( login()yöntemin ne anlama geldiği açıktır) için bir fırsat verecektir . Modele yapışmak, özellikle CRUD uygulamaları ile gerçekten ünlüdür ve belki de sizin için bir yoldur.


1

Denetleyiciler genellikle belirli bir kaynak (varlık sınıfı, veritabanındaki tablo) için oluşturulur, ancak uygulamanın belirli bir bölümünden sorumlu eylemleri gruplandırmak için de oluşturulabilir. Örneklerinizde bu, uygulamanın güvenliğini işleyen bir denetleyici olacaktır:

class SecurityController
{
    // can handle both the login page display and
    // the login page submission
    login(); 

    logout();

    register();

    // optional: confirm account after registration
    confirm();

    // displays the forgot password page
    forgotPassword();

    // displays the reset password page
    // and handle the form submission
    resetPassword();
}

Not : güvenlikle ilgili eylemleri ve kullanıcı profili eylemlerini aynı denetleyiciye koymayın; kullanıcı ile ilgili oldukları için mantıklı olabilir, ancak biri kimlik doğrulaması, diğeri ise e-posta, ad vb. güncellemeleri işlemelidir.

Kaynaklar için oluşturulmuş denetleyicilerle (diyelim ki Task), olağan CRUD eylemleriniz olur:

class TasksController
{
    // usually displays a paginated list of tasks
    index();

    // displays a certain task, based on an identifier
    show(id);

    // displays page with form and
    // handles form submission for creating
    // new tasks
    create();

    // same as create(), but for changing records
    update(id);     

    // displays confirmation message
    // and handles submissions in case of confirmation
    delete()
}

Tabii ki, aynı denetleyiciye ilgili kaynakları ekleme olanağınız vardır. Örneğin, varlığa sahip olduğunuzu Businessve her birinin birkaç BusinessServicevarlığı olduğunu varsayalım. Bunun için bir denetleyici şöyle görünebilir:

class BusinessController
{
    index();

    show(id);

    create();

    update(id);

    delete();

    // display the business services for a certain business
    listBusinessServices(businessId);

    // displays a certain business service
    showBusinessService(id);

    // create a new business service for a certain business
    createBusinessService(businessId);

    // updates a certain business service
    updateBusinessService(id);

    // deletes a certain business service
    deleteBusinessService(id);
}

Bu yaklaşım, ilgili çocuk varlıkları ana varlık olmadan var olamazlarsa mantıklıdır.

Bunlar benim önerilerim:

  • bir grup ilgili operasyona dayalı kontrolörler oluşturmak (güvenlik veya kaynaklar üzerindeki CRUD operasyonları gibi belirli sorumlulukları ele almak);
  • kaynak tabanlı denetleyiciler için gereksiz eylemler eklemeyin (kaynağı güncellemeniz gerekmiyorsa, güncelleme eylemini eklemeyin);
  • Bir şeyleri basitleştirmek için "özel" eylemler ekleyebilir (örneğin bir var Subscriptiongirişlerin sınırlı sayıda dayalı bir sisteme sahiptir varlık, adlı denetleyiciye yeni bir eylem ekleyebilir use()itibaren bir girdiyi çıkarılarak tek bir amacı vardır Subscription)
  • işleri basit tutun - denetleyicinizi çok sayıda eylem ve karmaşık mantıkla karıştırmayın, eylem sayısını azaltarak veya iki denetleyici yaparak işleri basitleştirmeye çalışın;
  • MVC odaklı bir çerçeve kullanıyorsanız, en iyi uygulama yönergelerini uygulayın (varsa).

Burada daha fazla okumak için bazı kaynaklar .


0

İki antagonistik tasarım "kuvveti" görüyorum (kontrolörlere özel olmayan):

  • bağlılık - denetleyiciler ilgili eylemleri gruplandırmalıdır
  • basitlik - denetleyiciler karmaşıklıklarını yönetmek için mümkün olduğunca küçük olmalıdır

Bağlılık açısından, her üç eylem de (giriş, çıkış, kayıt) ilişkilidir, ancak giriş ve çıkış, kayıttan çok daha fazladır. Anlamsal olarak ilişkilidir (biri diğerinin tersidir) ve büyük olasılıkla aynı hizmet nesnelerini de kullanacaktır (uygulamaları da uyumludur).

İlk önerim, oturum açma ve oturum kapatma işlemlerini tek bir denetleyicide gruplandırmak olacaktır. Ancak oturum açma ve oturum kapatma denetleyicisi uygulamaları o kadar basit değilse (örneğin oturum açma captcha, daha fazla kimlik doğrulama yöntemleri vb. Vardır), basitliği korumak için bunları LoginController ve LogoutController'a bölmek sorunum olmazdı. Bu karmaşıklık eşiğinin (denetleyiciyi bölmeye başlamanız gerektiğinde) biraz kişisel olduğu yer.

Ayrıca, kodunuzu başlangıçta ne tasarlarsanız tasarlayın, değiştikçe yeniden düzenleyebilirsiniz (ve yapmalısınız). Bu durumda, basit bir tasarıma (bir AuthenticationController'a sahip) başlamak oldukça tipiktir ve zamanla kodu karmaşıklaştıracak daha fazla gereksinim alırsınız. Karmaşıklık eşiğini geçtiğinde, iki denetleyiciye yeniden yansıtmalısınız.

BTW, kodunuz GET isteği ile kullanıcının oturumunu kapatmanızı önerir. Bu kötü bir fikir çünkü HTTP GET nullipotent olmalıdır (uygulamanın durumunu değiştirmemelidir).


0

İşte birkaç kural:

  • Denetleyici adı konunun adı olacak şekilde konu veya konuya göre düzenleyin.

  • Denetleyicinin adının URL'de kullanıcılarınız tarafından görülebileceğini unutmayın, bu yüzden tercihen onlar için anlamlı olmalıdır.

Bahsettiğiniz durumda (kimlik doğrulama) MVC ekibi sizin için kontrolörü zaten yazmıştır. Visual Studio 2013'ü açın ve Tamam'ı tıklatın.

File / New / Project... 
Search installed templates for "ASP.NET MVC4 Web Application"
Choose "Internet Application" / OK.

AccountController.cs, kullanıcı hesaplarını yönetmek için tüm yöntemleri içerir:

Login()
Logoff()
Register()
Disassociate()
Manage()
ExternalLogin()

Bu yüzden "Hesap" görünür konu adıyla "Kullanıcı hesapları ve kimlik doğrulaması" konusuna göre düzenlediler.


0

terminoloji

Bazı HTTP ile ilgili yöntemler "denetleyici" içeren bir sınıfı çağırmak büyük bir yanlış anlama olduğuna inanıyorum.

Denetleyici, isteği işleyen bir yöntemdir, ancak bu yöntemleri içeren bir sınıf değildir . Yani, index(), submit(), logout()kontrolörlerdir.

Bu tür yöntemleri içeren sınıfa, yalnızca bir grup denetleyici oluşturduğu ve "alt düzey" ad alanının rolünü oynadığı için "denetleyici" adı verilir. FP dilinde (Haskell gibi) sadece bir modül olurdu. Bu "denetleyici" sınıflarını, hizmetlere ve diğer program çapındaki öğelere başvurular dışında, OOP dillerinde mümkün olduğunca vatansız tutmak iyi bir uygulamadır.

Cevap

Terminoloji sıralandığında, soru "denetleyicileri ad alanlarına / modüllerine nasıl ayırmalıyız?" Bence cevap: tek bir isim alanı / modül içindeki kontrolörler aynı tür verilerle ilgilenmelidir . Örneğin, UserControllerfırsatlar öncelikle örnekleri ile Usersınıfının, ama bazen gerekirse diğer ilgili şeyler dokunuyor.

Yana login, logoutbu tür başka eylemler çoğunlukla oturum ile ilgileniyor ve bu muhtemelen en Onları içine koymak SessionControllerve indexsadece bir form yazdırır kontrolör, içine yerleştirilmelidir LoginPageControlleraçıkça giriş sayfasına uğraşan beri. HTML oluşturma ve oturum yönetimini tek bir sınıfa yerleştirmek biraz mantıklıdır ve bu da SRP'yi ve muhtemelen bir dizi başka iyi uygulamayı ihlal eder .

Genel prensip

Bir kod parçasını nereye koyacağınıza karar vermekte sorun yaşıyorsanız, uğraştığınız verilerle (ve türlerle) başlayın.


2
Üzgünüz, Kontrolör değil eylemler :)
JK01

@ JK01 Bunlar onlara böyle diyorsunuz. Bu terminoloji, biliyorsun. Ve bu işlevleri "denetleyiciler" (veya "işleyiciler") olarak adlandıran çerçeveler vardır, çünkü ad alanları / modüller zaten yeterli olduğundan, bunları sınıflar halinde düzenlemeyen birçok çerçeve vardır. İstediğiniz terimleri kullanabilirsiniz, sadece kelimelerdir, ancak bence daha az terime sahip olmak daha iyidir.
scriptin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.