テクニック:オブジェクト間で関数を移動する(M. Fowlerリファクタリング)

チョークでコードを開始する
テクニック: 作曲方法

本「 リファクタリング 」のリファクタリング手法の続き 既存のコードの改善Martin Fowler。

構文はC#で記述されますが、主なことはアイデアを理解することであり、他のプログラミング言語でも使用できます。

オブジェクト間で関数を移動する


  1. メソッドを移動するより頻繁に使用するクラス内で同じ本体を持つ新しいメソッドを作成する )。
    メソッドは、サブジェクト領域をよりよく反映するクラス内にある必要があります。
    から
    class View { private Shop shop; private List<User> FilterUsers(List<User> users, decimal koef) { List<User> activeUsers = new List<User>(); foreach(User user in users) { if(shop.IsActiveUser(user, koef)) { activeUsers.Add(user); } } return activeUsers; } } class Shop { public bool IsActiveUser(User user, decimal koef) { decimal rate = 1; if(koef > 1000) { rate = koef * 1.75; } return user.Boss || user.HasDiscount() && rate > 10; } } class User { private bool boss; public bool Boss { get { return boss; } } public bool HasDiscount() { // some condition } } 


     class View { private Shop shop; private List<User> FilterUsers(List<User> users, decimal koef) { List<User> activeUsers = new List<User>(); foreach(User user in users) { if(user.IsActiveUser(koef)) { activeUsers.Add(user); } } return activeUsers; } } class Shop { } class User { private bool boss; public bool Boss { get { return boss; } } public bool HasDiscount() { // some condition } public bool IsActiveUser(decimal koef) { decimal rate = 1; if(koef > 1000) { rate = koef * 1,75; } return Boss || HasDiscount() && rate > 10; } } 

  2. フィールドを移動するターゲットクラスに新しいフィールドを作成する )。
    フィールドは、サブジェクト領域をよりよく反映するクラス内にある必要があります
    から
     class Shop { private decimal rate; private DiscountType discountType; public Shop(DiscountType discountType, decimal rate) { this.rate = rate; this.discountType = discountType; } public decimal Rate { get{ return rate; } set{ rate = value; } } public bool HasDiscount(DateTime from, DateTime to) { // some calculation of flag return discountType.IsValid(rate) && flag; } public decimal GetDiscount(decimal amount, bool fullSum) { // some calculation of koef return discountType.GetAmount(rate, fullSum) * koef; } } class DiscountType { public bool IsValid(decimal rate) { // some calculation using rate } public decimal GetAmount(decimal rate, bool fullSum) { // some calculation using rate } } 


     class Shop { private DiscountType discountType; public Shop(DiscountType discountType) { this.discountType = discountType; } public bool HasDiscount(DateTime from, DateTime to) { // some calculation of flag return discountType.IsValid() && flag; } public decimal GetDiscount(decimal amount, bool fullSum) { // some calculation of koef return discountType.GetAmount() * koef; } } class DiscountType { private decimal rate; public DiscountType(decimal rate) { this.rate = rate; } public decimal Rate { get{ return rate; } set{ rate = value; } } public bool IsValid() { // some calculation using rate } public decimal GetAmount(bool fullSum) { // some calculation using rate } } 

  3. クラスを強調表示し ます新しいクラスを作成し、フィールドとメソッドを古いクラスから新しいクラスに移動します )。
    クラスには独自のデータモデルとそれを操作するメソッドが含まれている必要があります。そうでない場合、クラスはGodオブジェクトになります。
    から
     class User { private string name; private string street; private string city; public string Name { get{ return name; } set{ name = value; } } public string Street { get{ return street; } set{ city = value; } } public string City { get{ return city; } set{ city = value; } } public string GetAddressInfo() { return string.Format("{0} \ {1}", city, street); } } 


     class User { private string name; private Address address; public string Name { get{ return name; } set{ name = value; } } public string GetAddressInfo() { return address.GetFullAddress(); } } class Address { private string city; private string street; public string Street { get{ return street; } set{ city = value; } } public string City { get{ return city; } set{ city = value; } } public string GetFullAddress() { return string.Format("Adress: {0} \ {1}", city, street); } } 

  4. クラスのインライン化すべての関数を別のクラスに移動し、元のクラスを削除します)。
    クラスの関数が少なすぎます。
    から
     class User { private string name; private Address address; public string Name { get{ return name; } set{ name = value; } } public Address GetAddress() { return address } } class Address { private string areaCode; private string country; public string AreaCode { get{ return areaCode; } set{ areaCode = value; } } public string Country { get{ return country; } set{ country = value; } } } 


     class User { private string name; private string areaCode; private string country; public string AreaCode { get{ return areaCode; } set{ areaCode = value; } } public string Country { get{ return country; } set{ country = value; } } public string Name { get{ return name; } set{ name = value; } } } 

  5. 委任の 非表示(委任を非表示にするメソッドを作成 )。
    カプセル化、システムの一部。
    から
     class View { private void Init() { // some code User manager = currentUser.Office.Manager; } } class User { private Department department; public Department Office { get{ return department; } set{ department = value; } } } class Department { private User manager; public Department(User manager) { this.manager = manager; } public User Manager { get{ return manager; } } } 


     class View { private void Init() { // some code User manager = currentUser.Manager; } } class User { private Department department; public User Manager { get{ return department.Manager; } } } class Department { private User manager; public Department(User manager) { this.manager = manager; } public User Manager { get{ return manager; } } } 

  6. ブローカーを削除 しますクライアントがデリゲートに直接連絡するようにします )。
    クラスは単純な委任で忙しすぎます。
    から
     class View { private void Init() { // some code User manager = currentUser.Manager; decimal rate = currentUser.Rate; } } class User { private Department department; private UserType userType; public User Manager { get{ return department.Manager; } } public decimal Rate { get{ return userType.Rate; } } } class Department { private User manager; public User Manager { get{ return manager; } } } class UserType { private decimal rate; public decimal Rate { get{ return rate; } } } 


     class View { private void Init() { // some code User manager = currentUser.Office.Manager; decimal rate = currentUser.Type.Rate; } } class User { private Department department; private UserType userType; public Department Office { get{ return department; } } public UserType Type { get{ return userType; } } } class Department { private User manager; public User Manager { get{ return manager; } } } class UserType { private decimal rate; public decimal Rate { get{ return rate; } } } 

  7. 外部メソッドの導入クライアントで、サーバークラスが1番目のパラメーターとして渡されるメソッドを追加します )。
    メソッドを導入する必要がありますが、クラスを変更する可能性はありません。
    から
     class View { private string GetUserName() { // some code return "\"" + userName + "\""; } private string GetCompanyName() { // some code return "\"" + companyName + "\""; } } 


     class View { private string GetUserName() { // some code return userName.InDoubleQuote(); } private string GetCompanyName() { // some code return companyName.InDoubleQuote(); } } static class StringExtension { public static string InDoubleQuote(this string str) { return "\"" + str + "\""; } } 

  8. ローカル拡張の導入クラスのラッパーを作成(または継承を使用)し、必要なメソッドを追加します )。
    メソッドを導入する必要がありますが、クラスを変更する方法はありません。
    から
     sealed class Account { public decimal CalculateSum() { // calculation summ return summ; } } 


     class ImportantAccount { private Account account; public decimal CalculateMaxSum() { // calculation rate return account.CalculateSum() * rate; } } 


利益相反(レビューの一環として)。


原則として、校閲者とcomitt-errの間で生じるすべての論争/不一致は、次のように分類できます。

「技術:データ編成」をさらに続けていきたいと思います。

Source: https://habr.com/ru/post/J174779/


All Articles