Дизайн класса цепочки - PullRequest
1 голос
/ 27 мая 2011

У меня есть сторонняя библиотека C # для операций ldap. Он выполняет все операции над объектом подключения, как показано ниже:

LdapConnection connection = new LdapConnetion(Settings settings);
connection.Search(searchOU, filter,...);

который я чувствую не читаемым. Я хочу написать обертку вокруг него, чтобы иметь возможность писать код, как показано ниже:

Как я хотел бы иметь разные классы Ldap, такие как

public class AD: LdapServer { }
public class OpenLdap: LdapServer { }

, а затем

AD myldap = new AD(Settings settings);
myldap.Users.Search(searchOU, filter,...)
myldap.Users.Add(searchOU, filter,...)
myldap.Users.Delete(searchOU, filter,...)

Я думаю о шаблоне проектирования Proxy, но мне в голову не приходит горячая мысль, чтобы это сделать. Какие у меня должны быть занятия и т. Д.

Любая помощь?

Ответы [ 2 ]

0 голосов
/ 27 мая 2011

Решение, опубликованное выше, наследуется от LdapConnection. Это хорошо, если вы хотите сохранить цепочку наследования, но я не думаю, что это необходимо в вашем случае. Вы просто хотите настроить и упростить интерфейс.

Шаблон проектирования прокси наследует от базового объекта, так что прокси-объект может использоваться везде, где требуется базовый объект, это хорошо, если вы хотите «внедрить» дополнительные функциональные возможности в класс без реализации клиентами этого класса , Я не думаю, что это ваше намерение здесь?

Большая проблема с решением, опубликованным выше, заключается в том, что (поскольку он наследуется непосредственно от LdapConnection), вы можете вызвать поиск двумя способами, например:

Settings settings = new Settings();
AD myAD = new AD(settings);

object results = myAD.Users.Search();
// OR
object results2 = myAD.Search();

Как я уверен, вы можете видеть из кода, оба они вызывают один и тот же базовый метод. Но, на мой взгляд, это еще больше сбивает с толку разработчиков, чем просто использование ванильного объекта LdapConnection. Я всегда думал: «В чем разница между этими, казалось бы, одинаковыми методами?» Еще хуже, если вы добавите некоторый пользовательский код в метод поиска UsersWrapper, вы не всегда сможете гарантировать, что он будет вызван. У разработчика всегда будет возможность вызывать Поиск напрямую, не обращаясь к UsersWrapper.

Фаулер в своей книге PoEAA определяет паттерн, называемый шлюзом. Это способ упростить и настроить интерфейс для внешней системы или библиотеки.

public class AD
{
    private LdapConnection ldapConn;
    private UsersWrapper users;

    public AD()
    {
        this.ldapConn = new LdapConnection(new Settings(/* configure settings here*/));
        this.users = new UsersWrapper(this.ldapConn);
    }

    public UsersWrapper Users
    {
        get
        {
            return this.users;
        }
    }

    public class UsersWrapper
    {
        private LdapConnection ldapConn;

        public UsersWrapper(LdapConnection ldapConn)
        {
            this.ldapConn = ldapConn;
        }

        public object Search()
        {
            return this.ldapConn.Search();
        }

        public void Add(object something)
        {
            this.ldapConn.Add(something);
        }

        public void Delete(object something)
        {
            this.ldapConn.Delete(something);
        }
    }
}

Затем это можно использовать так:

AD myAD = new AD();
object results = myAD.Users.Search();

Здесь вы можете видеть, что объект LdapConnection полностью инкапсулирован внутри класса, и существует только один способ вызова каждого метода. Более того, настройка LdapConnection также полностью инкапсулирована. Код, использующий этот класс, не должен беспокоиться о том, как его настроить. Настройки определяются только в одном месте (в этом классе, а не распространяются по всему приложению).

Единственным недостатком является то, что вы теряете цепочку наследования обратно в LdapConnection, но я не думаю, что это необходимо в вашем случае.

0 голосов
/ 27 мая 2011

Хорошо, если вы просто хотите разделить методы на объекты, на которые они действуют (например, в вашем примере добавьте .Users. Перед вызовом метода), вы можете сделать что-то похожее на это. получите правильные параметры метода и возвращаемые типы для вашей библиотеки, я только что использовал объект здесь.

Это то, что вы ищете?

public class AD : LdapConnection
{
    private UsersWrapper users;

    public AD(Settings settings) : base(settings)
    {
        this.users = new UsersWrapper(this);
    }

    public UsersWrapper Users
    {
        get
        {
            return this.users;
        }
    }

    public class UsersWrapper
    {
        private AD parent;

        public UsersWrapper(AD parent)
        {
            this.parent = parent;
        }

        public object Search()
        {
            return this.parent.Search();
        }

        public void Add(object something)
        {
            this.parent.Add(something);
        }

        public void Delete(object something)
        {
            this.parent.Delete(something);
        }
    }
}

Это может быть использовано следующим образом:

Settings settings = new Settings();
AD myAD = new AD(settings);

object results = myAD.Users.Search();

Помните, что это не просто "оболочка", потому что она на самом деле наследует от базового класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...