Определение
Цели
public Customer Customer
{
get { return customer; }
}
}
public class Customer {
public string Name
{ get; }
public BillingPlan GetBillingPlan();
public PaymentHistory GetHistory();
}
plan = BillingPlan.GetBasicPlan();
else
plan = customer.GetBillingPlan();
String customerName;
if (customer == null)
customerName = "occupant";
else
customerName = customer.Name;
int weeksDelinquent; // Количество неоплаченных недель
if (customer == null)
weeksDelinquent = 0;
else
weeksDelinquent =
customer.GetHistory().GetWeeksDelinquentLastYear();
return false;
}
}
public class NullCustomer : Customer
{
public override bool IsNull()
{
return true;
}
}
public class Customer {
public static Customer CreateNullCustomer() {
return new NullCustomer();
}
}
public class Site {
public Customer Customer {
get {
if (customer == null)
return Customer.CreateNullCustomer();
else
return customer;
}
}
}
plan = BillingPlan.GetBasicPlan();
else
plan = customer.GetBillingPlan();
String customerName;
if (customer.IsNull())
customerName = "occupant";
else
customerName = customer.Name;
int weeksDelinquent;
if (customer.IsNull())
weeksDelinquent = 0;
else
weeksDelinquent =
customer.GetHistory().GetWeeksDelinquentLastYear();
public override string Name
{
get { return "occupant"; }
}
public override BillingPlan GetBillingPlan()
{
return BillingPlan.GetBasicPlan();
}
}
BillingPlan plan;
plan = customer.GetBillingPlan();
String customerName;
customerName = customer.Name;
public class PaymentHistory
{
public static PaymentHistory CreateNullPaymentHistory()
{
return new NullPaymentHistory();
}
}
public class NullPaymentHistory : PaymentHistory
{
public override int GetWeeksDelinquentLastYear()
{
return 0;
}
}
public override PaymentHistory GetHistory()
{
return PaymentHistory.CreateNullPaymentHistory();
}
}
int weeksDelinquent;
weeksDelinquent =
customer.GetHistory().GetWeeksDelinquentLastYear();
Краткое описание
Образовать из аналогичных шагов методы с
одинаковой сигнатурой, чтобы исходные
методы стали одинаковыми. После этого
поместить их в родительский класс.
● С помощью «Подъѐма метода» переместите
идентичные методы в родительский класс.
● Переименуйте различающиеся методы так,
чтобы сигнатуры всех методов на каждом шаге
были одинаковы.
● Примените «Подъѐм метода» к одному из
исходных методов. Определите их сигнатуры как
абстрактные методы родительского класса.
public class Customer
{
public string GetStatement()
{
string result = "Учёт аренды для " + Name + "\n";
foreach (Rental rental in Rentals)
result += "\t" + rental.Movie.Title + "\t" +
rental.Charge.ToString() + "\n";
result += "Сумма задолженности составляет: " +
GetTotalCharge().ToString() + "\n";
result += "Вы заработали " +
GetTotalFrequentRenterPoints().ToString() +
" очков за активность";
return result;
}
}
"
";
foreach (Rental rental in Rentals)
result += rental.Movie.Title + " " +
rental.Charge.ToString() + "
";
result += "
Сумма задолженности составляет " + GetTotalCharge().ToString() + "
";
result += "Вы заработали " + GetTotalFrequentRenterPoints().ToString() +
"
return result;
}
}
public class Customer {
public string GetStatement() {
return (new TextStatement()).GetValue(this);
}
public string GetHTMLStatement(Customer customer) {
return (new HTMLStatement()).GetValue(this);
}
}
public class TextStatement : Statement {
public string GetValue(Customer customer);
}
public class HTMLStatement : Statement {
public string GetValue(Customer customer);
}
public string GetValue(Customer customer)
{
string result = "Учёт аренды для " + customer.Name + "\n";
foreach (Rental rental in customer.Rentals)
result += "\t" + rental.Movie.Title + "\t" +
rental.Charge.ToString() + "\n";
result += "Сумма задолженности составляет: " +
customer.GetTotalCharge().ToString() + "\n";
result += "Вы заработали " +
customer.GetTotalFrequentRenterPoints().ToString() +
" очков за активность";
return result;
}
}
public class TextStatement : Statement
{
private string GetHeaderString(Customer customer) {
return "Учёт аренды для " + customer.Name + "\n";
}
public string GetValue(Customer customer) {
string result = GetHeaderString(customer);
...
}
}
return "
";
}
public string GetValue(Customer customer)
{
string result = GetHeaderString(customer);
...
}
}
rental.Charge.ToString() + "\n";
}
private string GetFooterString(Customer customer) {
return "
Сумма задолженности составляет " + customer.GetTotalCharge().ToString() + "
" + customer.GetTotalFrequentRenterPoints().ToString() +
"Вы заработали " +
"
}
}
Аналогично поступим с остальными элементами счѐта:
return rental.Movie.Title + " " +
rental.Charge.ToString() + "
";
}
private string GetFooterString(Customer customer) {
return "
Сумма задолженности составляет " + customer.GetTotalCharge().ToString() + "
" + customer.GetTotalFrequentRenterPoints().ToString() +
"Вы заработали " +
"
}
}
public string GetValue(Customer customer)
{
string result = GetHeaderString(customer);
foreach (Rental rental in customer.Rentals)
result += GetRentalString(rental);
result += GetFooterString(customer);
return result;
}
}
protected abstract string GetFooterString(Customer customer);
public string GetValue(Customer customer)
{
string result = GetHeaderString(customer);
foreach (Rental rental in customer.Rentals)
result += GetRentalString(rental);
result += GetFooterString(customer);
return result;
}
}
Необходимо поднять метод GetValue в родительский класс. При
подъѐме остальные методы надо объявить абстрактными:
● Удалите простые методы делегирования.
● Замените все другие делегирования
обращениями к самому объекту.
● Удалите поле делегирования.
public class Employee
{
Person person = new Person();
public string Name
{
get { return person.Name; }
set { person.Name = value; }
}
public override string ToString()
{
return "Emp: " + person.GetLastName();
}
}
}
public string GetLastName()
{
return name.Substring(name.LastIndexOf(' ') + 1);
}
}
public class Employee : Person
{
Person person;
public Employee()
{
person = this;
}
}
public class Employee : Person
{
Person person;
public string Name
{
get { return person.Name; }
set { person.Name = value; }
}
public override string ToString()
{
return "Emp: " + GetLastName();
}
}
}
public string GetLastName() {
return name.Substring(name.LastIndexOf(' ') + 1);
}
}
public class Employee : Person {
public override string ToString() {
return "Emp: " + GetLastName();
}
}
● Для каждого константного метода объявите
соответствующие поля.
● Объявите защищенный конструктор для инициализации
полей.
● Измените имеющиеся конструкторы так, чтобы они
использовали новый конструктор.
● Реализуйте каждый константный метод так, чтобы он
возвращал поле, и удалите метод из подкласса.
public abstract char GetCode();
}
public class Male : Person {
public override bool IsMale()
{
return true;
}
public override char GetCode()
{
return 'M';
}
}
return 'F';
}
}
return new Male();
}
public static Person CreateFemale()
{
return new Female();
}
}
Person person = new Male();
Person person = Person.CreateMale();
Заменяем вызовы конструкторов на вызовы фабричных методов,
тем самым избавляясь от ссылок на подклассы в клиентском коде:
public abstract class Person
{
private bool isMale;
private char code;
protected Person(bool isMale, char code)
{
this.isMale = isMale;
this.code = code;
}
}
public Male()
: base(true, 'M')
{ }
}
public class Female : Person
{
public Female()
: base(false, 'F')
{ }
}
public abstract class Person
{
public bool IsMale()
{
return isMale;
}
}
public class Male : Person
{
public override bool IsMale()
{
return true;
}
}
public class Person
{
public static Person CreateMale()
{
return new Person(true, 'M');
}
public static Person CreateFemale()
{
return new Person(false, 'F');
}
}
Краткое описание
Необходимо создать два метода — один
для запроса и один для модификации.
● Модифицируйте исходный метод так, чтобы он
возвращал результат обращения к запросу.
● Для каждого вызова замените одно обращение к
исходному методу вызовом запроса. Вызов
запроса поместите после вызова исходного
метода.
● Объявите тип возвращаемого значения void и
удалите выражения return.
public string FoundMiscreant(List foreach (string man in people) { if (man == "Don") { SendAlert(); } if (man == "John") { SendAlert(); return "John"; } return ""; } private void CheckSecurity(List string found = FoundMiscreant(people); } Функция используется следующим образом:
return "Don";
}
SomeLaterCode(found);
public string FoundPeople(List foreach (string man in people) if (man == "Don") return "Don"; if (man == "John") return "John"; } return ""; }
{
{
public string FoundMiscreant(List foreach (string man in people) { if (man == "Don") { SendAlert(); return FoundPeople(people); } if (man == "John") { SendAlert(); return FoundPeople(people); } return FoundPeople(people); }
}
private void CheckSecurity(List FoundMiscreant(people); string found = FoundPeople(people); }
{
SomeLaterCode(found);
foreach (string man in people) {
if (man == "Don")
{
SendAlert();
return;
}
if (man == "John")
{
SendAlert();
return;
}
}
return;
}
if (FoundPeople(people) != "")
SendAlert();
}
private void CheckSecurity(List SendAlert(people); string found = FoundPeople(people); } Клиентский код после рефакторинга:
{
SomeLaterCode(found);
● Удалите метод посредник.
private Department department;
public Person Manager {
get { return department.Manager; }
}
}
public class Department {
private Person manager;
public Department(Person manager) {
this.manager = manager;
}
public Person Manager {
get { return manager; }
}
}
public class Person
{
private Department department;
public Department Department
{
get { return department; }
}
}
В первую очередь создаѐм метод доступа к делегату:
manager = john.Department.Manager;
Возможно, что одним клиентам нужно оставить методы-делегаты,
а от других скрыть. В этом случае необходимо сохранить
некоторые простые делегирования.
Краткое описание
Необходимо вместо значений передать
объект полностью.
● Удалите из вызывающего метода код,
который получает удалѐнные параметры.
public class HeatingPlan {
TempRange range;
public bool WithinRange(int low, int high) {
return (low >= range.Low && high <= range.High);
}
}
public class Room {
public bool WithinPlan(HeatingPlan plan) {
int low = DaysTempRange.Low;
int high = DaysTempRange.High;
return plan.WithinRange(low, high);
}
}
public class HeatingPlan {
public bool WithinRange(TempRange roomRange,
int low, int high) {
return (low >= range.Low && high <= range.High);
}
}
public class Room {
public bool WithinPlan(HeatingPlan plan) {
int low = DaysTempRange.Low;
int high = DaysTempRange.High;
return plan.WithinRange(DaysTempRange, low, high);
}
}
public class HeatingPlan
{
TempRange range;
public bool WithinRange(TempRange roomRange,
int low, int high)
{
return (roomRange.Low >= range.Low &&
roomRange.High <= range.High);
}
}
int low = DaysTempRange.Low;
int high = DaysTempRange.High;
return plan.WithinRange(DaysTempRange);
}
}
public class HeatingPlan
{
public bool WithinRange(TempRange roomRange)
{
return range.Includes(roomRange);
}
}
Удалить класс обѐртку и реализовать
дополнительную функциональсть в виде
методов расширения.
В данном примере к классу String добавляется метод подсчѐта
количества слов:
public static class StringExtensions {
public static int WordCount(this String str) {
return str.Split(
new char[] { ' ', '.', '?' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
}
string s = "Hello Extension Methods";
int i = s.WordCount();
Пример использования:
● В классе-обѐртке заменить реализацию
расширенной функциональности
делегированием методу расширения.
● Удалить класс-обѐртку, когда он будет
содержать только делегирующие методы.
public class EnhancedSqlConnection : IDbConnection {
private SqlConnection wrapped;
public EnhancedSqlConnection() {
this.wrapped = new SqlConnection();
}
public void RestoreDatabase(string backupFileName) {
// ... implementation
}
public void Open() {
wrapped.Open();
}
public IDbTransaction BeginTransaction() {
wrapped.BeginTransaction();
}
}
public static class EnhancedSqlConnectionExtension
{
public static void RestoreDatabase(
this SqlConnection connection,
string backupFileName)
{
// ... implementation
}
}
public class EnhancedSqlConnection : IDbConnection {
private SqlConnection wrapped;
public EnhancedSqlConnection() {
this.wrapped = new SqlConnection();
}
public void RestoreDatabase(string backupFileName) {
wrapped.RestoreDatabase(backupFileName);
}
}
Повторив операцию для каждого метода расширения, получим
класс, который содержит только делегирующие методы. После
этого можно удалить исходный класс и создавать вместо него
класс SqlConnection.
Если не удалось найти и скачать презентацию, Вы можете заказать его на нашем сайте. Мы постараемся найти нужный Вам материал и отправим по электронной почте. Не стесняйтесь обращаться к нам, если у вас возникли вопросы или пожелания:
Email: Нажмите что бы посмотреть