[Professional ASP.NET Design Pattern 读书笔记系列] 02 分解类型的类型
1. GoF描述23中设计模式时遵循了哪些原则?
1)Pattern Name和Classification 类姓名和分类:类型名规定了这种Pattern的名字,Classification表明它是属于Creational、Structural还是Behavioral中的哪一种。
2)Intent 意图:表明这个发Pattern是用来解决什么问题的,以及它解决这个问题为什么有用。
3)Also Known As同时也是:说明了这个类型可能还有的别的名字。
4)Motivation 动机:描述了这个Pattern可以应用的一种场景。
5)Applicability 可应用性:列出了的使用这种Pattern可能带来好处的几种场景。
6)Structure结构:是模式的图形化表示,包括这个模式所涉及的对象的分工和合作。通常这是由UML表来表示的。
7)Participants参与者:列举了这个设计模式可能涉及的所有对象。
8)Collaborations合作:描述了参与者是如何合作形成一个设计模式的。
9)Consequences结果:列出了使用这种设计模式的好处和缺点。
10)Implementations 实现:列出了使用这种设计模式的一些最佳实践。
11)Sample code:展示了设计模式的一种实现。
12)Known Uses:展示了设计模式在真实场景里的应用。
13)Related Patterns相关模式:列出了与这个设计模式可以相合作和工作的设计模式。
2.以上的原则有哪些简化?
1. Name and intent
2. UML Diagram
3. Code Example
3. Creational组包含了哪些模式?
1. Abstract Factory抽象工厂:使用接口来创造一系列的对象。
2. Factory 工厂模式:使用类来实现创造一个实际的对象才能完成的功能。
3. Builder 构造者模式:通过为类分离出多个构成方法,为类设计多个版本。
4. Prototype:允许从一个原型体实例进行拷贝和克隆,而不是创造新的实例。
5. Singleton:只允许类实现一个对象,然后在程序多处对其进行引用。
4. Structural组包含了哪些模式?
1. Adapter:使实现了不同接口的类能够一起功能。
2. Bridge:将类的抽象和实现分离,从而使得类的抽象和实现可以各自变化。
3. Composite:允许一组对象可以像一个实例一样被对待。
4. Decorator:可以动态拓展一个类的行为。
5. Facade:提供一个简单的接口来控制一系列复杂的接口。
6. Flyweight:提供一个种方法来与很多很小的类分享数据。
7. Proxy:为一个复杂的很难实现的类提供一个占位符。
5. Behavioral组包含哪些模式?
1. Chain of Responsibility:允许命令被动态连接起来去处理一个请求。
2. Command:将一个方法包装为一个对象,然后通过invoker来执行。
3. Interpreter:指定了如何评价语言的句子。
4. Iterator:提供了一种以统一的模式来遍历对象的方法。
5. Mediator:定义了一个对象,可以使得其余两个对象在不知道对方的情况下进行通信。
6. Mementor:允许将对象恢复到上一个状态。
7. Observer:定义了一种方法,使得一个类发生的改变可以被其它类获知。
8. State:允许一个对象可以根据另外一个状态对象的改变而使自己的行为改变。
9. Strategy:设计一种算法使得对象可以在运行时改变状态。
10. Template method:对算法的流程进行控制,但是具体行为的话允许子类进行覆盖。
11. Visitor:使类可以执行新功能,但是结构不改变。
6. 一个失败的架构是怎样的?
假设一个简单的电子商城的架构,里面有三个类,分别如下:
namespace ASPPatterns.Chap2.Service
{
class Product
{
}public class ProductRepository
{
public IList<Product> GetAllProductsIn(int categoryID)
{
IList<Product> products = new List<Product>();//Database operation to populate products ..
return products;
}public class ProductService
{
private ProductRepository _productRepository;public ProductService()
{
_productRepository = new ProductRepository();
}public IList<Product> GetAllProductsIn(int categoryId)
{
IList<Product> products;
string storageKey = string.Format("products_in_category_id_{0}", categoryID);products = (List<Product>)System.Web.HttpContext.Current.Cache.Get(storageKey);
if (products == null)
{
products = _productRepository.GetAllProductsIn(categoryId);HttpContext.Current.Cache.Insert(storageKey, products);
}return products;
}
}
这里程序的结构非常清楚,就是ProductService提供GetAllProductsIn这个方法,如果cache内有这个ID则返回cache内的内容,如果没有,则通过ProductRepository去访问数据库。这里架构存在三个缺陷:
1. 两个类之间的耦合度太高。 ProductService里面直接调用了ProductRepository的API,因此如果ProductRepository的API改变,则ProductService会受到影响。
2. ProductService代码无法测试。因为要完全测试ProductService的话必须要实现完全ProductRepository。另外,HTTPContext不是在测试的时候那么好取得的。
3. 程序依赖HTTP context进行缓存。因此如果要换用Velocity或者Memcached,就必须修改该类。
7. 如何实现ProductService与ProductRepository脱耦?
1)使用Dependency Inversion Principle依赖反转。也就是说,将ProductService要是用到的ProductRepository的GetAllProductsIn方法抽象为一个interface,这样ProductService在调用该方法时不再直接使用该类的方法,而是通过该接口来调用。由于接口可能有多种实现,所以只要改变接口的实现,就可以得到不同的GetAllProductsIn的方法。
但是,这样做之后脱耦仍然不彻底:
public class ProductService
{
private IProfuctRepository _productRepository;
public ProductService()
{
_productRepository = new ProductRepository();
}
public IList<Product> GetAllProductsIn(int categoryId)
{
…….
}
}
可见该接口仍然需要在ProductService内部指向ProductRepository对象,因此如果ProductRepository改变的话,ProductService仍然有可能需要改变。为了改进,我们继续采用:
2)使用Dependency Injection Principle依赖注入方法。
public class ProductService
{
private IProfuctRepository _productRepository;
public ProductService(IProductRepository productRepository)
{
_productRepository = productRepository;
}
public IList<Product> GetAllProductsIn(int categoryId)
{
…….
}
}
这样ProductService需要依赖的实现了IProductRepository接口的对象在类的构造函数中直接注入而不是在该类中实现。
8. 如何实现ProductService和HttpContext的脱耦:
要实现ProductService和HttpContext的脱耦,我们同样可以使用Interface的方法,但是这样里的但难点是,我们试图实现的Interface,包括如下三个方法:
public interface ICacheStorage
{
void Remove(string key);
void Store(string key, object data);
T Retrieve<T>(string key);
}
但是这三个方法在HttpContext这个类里面并没有实现,因为代码不是我们写的,所以我们不能直接使用ICacheStorage ics = new HttpContext()这样的方法。
为了同样能够使用Interface,我们引入了Adapter的设计模式,既通过Adapter类把我们要的interface和我们要的类通过一个转换类结合起来。在Adapter类里面我们实现这三个Remove ,Store和Retrieve方法,而三个方法内部再依靠HttpContext来实现。