2008年6月29日

模式笔记五: 创建型模式

=单例模式=

单例模式需要考虑的重要问题是其生存周期问题,一种是不死鸟,永远不销毁,最为简单,但是占用了资源
另一种是有生存周期, 但是又要考虑其引用可能无效的问题
* Lifetime: Dead reference
* Double check locking

=工厂模式=
工厂模式是很常用的模式, 常见的有
*简单工厂
*抽象工厂



*工厂方法



=生成器模式=


=原型模式=


这里只是简单地用相应类图来表示, 个中滋味, 在应用中自己慢慢体会吧
相似的一点是抽象的东西有具体的实现, 至于到底用哪个具体的实现, 交给工厂来创建吧
至于这个工厂, 视问题域的复杂性,可以是抽象的, 也可以是具体的,工厂模式大体如此

posted @ 2008-08-11 17:19 fantasyamin 阅读(192) | 评论 (0)编辑 收藏

模式笔记四:GRASP模式概论

General Responsibility Assignment Software Patterns  通用职责分配软件模式

模式名称

描述(问题/解决方案)

信息专家模式Information Expert

问题:对象设计和职责分配的一般原则是什么?
解决方案:将职责分配给拥有履行一个职责所必需信息的类--即信息专家。(也就是将职责分配给一个类,这个类必须拥有履行这个职责所需要的信息。)

创建者模式Creator

问题:谁应该负责产生类的实例(对应于GoF设计模式系列里的工厂模式
解决方案:如果符合下面的一个或多个条件,则将创建类A实例的职责分配给类B.
.
B聚合类A的对象。
.
B包含类A的对象。
.
B记录类A对象的实例。
.
B密切使用类A的对象。
.
B初始化数据并在创建类A的实例时传递给类A(类B是创建类A实例的一个专家)
在以上情况下,类B是类A对象的创建者。

控制器模式

Controller

问题:谁处理一个系统事件?
解决方案:当类代表下列一种情况时,为它分配处理系统事件消息的职责。
.
代表整个系统、设备或子系统(外观控制器)。
.
代表系统事件发生的用例场景(用例或回话控制器)。

低耦合Low Coupling

 

问题:如何支持低依赖性以及增加重用性?
解决方案:分配职责时使(不必要的)耦合保持为最低。

高内聚High Cohesion

 

问题:如何让复杂性可管理?
解决方案:分配职责时使内聚保持为最高。

多态模式Polymorphism

问题:当行为随类型变化而变化时谁来负责处理这些变化?
解决方案:当类型变化导致另一个行为或导致行为变化时,应用多态操作将行为的职责分配到引起行为变化的类型。

纯虚构模式Pure Fabrication

问题:当不想破坏高内聚和低耦合的设计原则时,谁来负责处理这些变化?
解决方案:将一组高内聚的职责分配给一个虚构的或处理方便的行为类,它并不是问题域中的概念,而是虚构的事务,以达到支持高内聚、低耦合和重用的目的。

中介模式Indirection

问题:如何分配职责以避免直接耦合?
解决方案:分配职责给中间对象以协调组件或服务之间的操作,使得它们不直接耦合。

受保护变化模式Protected Variations

问题:如何分配职责给对象、子系统和系统,使得这些元素中的变化或不稳定的点不会对其他元素产生不利影响?
解决方案:找出预计有变化或不稳定的元素,为其创建稳定的接口而分配职责。

这些更象是一些OOD的原则, 模式会有很多, 但是万变不离其宗, 大都遵循着一些基本的原则
  • OCP(Open-Closed Principle)
  • DIP(Dependency Inversion Principle)
  • LSP(Liskov Substitution Principle)
  • ISP(Interface Insolation Principle)
  • SRP(Single Resposibility Principle)
  • CARP(Composite/Aggregate Reuse Principle)
  • LoD(Law Of Demeter):don't talk to stranger
之后我们来详细讨论这些原则

posted @ 2008-08-11 15:27 fantasyamin 阅读(727) | 评论 (0)编辑 收藏

模式笔记三:GOF设计模式

大名鼎鼎的GOF的设计模式是最著名的一本里程碑的作品
=模式分类=

=模式之间的关系=

=如何应用模式=
DP中的引言说得很好,如何应该模式来解决设计问题
* 寻找合适的对象
对象包括数据和操作, 对象在收到请求(或消息)后, 执行相应的操作
客户请求是使对象执行操作的唯一方法, 操作又是对象改变内部数据的唯一方法
(这就是封装的意义,之所以强调对象的成员应该是私有的原因)

OOD最困难的部分就是将系统分解成对象集合,因为要考虑许多因素:
封装,粒度,信赖关系,灵活性,性能,演化,复用等等,它们之间也互相有所影响或冲突.

设计模式可以帮助我们确定那些并不明显的抽象和描述这些抽象的对象,如Strategy, State,etc.

==决定对象的粒度==
如何决定对象的大小,数目以及范围呢, 设计模式亦有所帮助:
Facade 描述了怎样用对象表示完整的子系统
Flyweight
Abstact Factory
Builder
Visitor
Command

==指定对象接口==
对象接口描述了该对象所能接受的全部请求的集合, 也就是它能够提供哪些服务(方法)
当给对象发送请求时, 所引起的具体操作既与请求本身有关,又与接受对象有关
支持相同请求的不同对象可能对请求激发的操作有不同的实现(动态绑定和多态)

而设计模式通过确定接口的主要组成部分及经接口发送的数据类型, 来帮助你定义接口.
DP也许还会告诉你接口中不应包括哪些东西, 比如Memento模式所规定的接口
DP也指定了接口之间的关系,特别地,它常要求一些类具有相同或相似的接口,或对一些类的接口作出一些限制
如Decorator, Proxy模式要求修饰/代理对象和被修饰/受代理的对象接口保持一致
Visitor模式中Vistor接口必须反映能访问的对象的所有类

==描述对象的实现==
* 类继承还是接口继承呢
* 针对接口编程,而不是针对实现编程

==运用复用机制==
1.优先使用对象组合,而不是类继承
2.委托
3.继承和泛型的比较

==关联运行时刻和编译时刻的结构==

==设计应支持变化==
* 设计中常出现的问题
** 通过显式地指定一个类来创建对象
*** Factory , Prototype
** 对特殊操作的依赖
*** Chain of Reponsibility, Command
** 对硬件和软件平台的依赖
*** Abstract Factory, Bridge
** 对对象表示或实现的依赖
** 算法依赖
** 紧耦合
*** Abstract Factory, command, facade, mediator, observere,chain of responsibility
** 通过生成子类来扩充功能
*** Bridge, Chain of Reponsibility, composite, Decorator, Observer, Strategy
** 不能方便地对类进行修改
*** Adapter, Decorator, visitor

=如何选择设计模式=
* 考虑设计模式是如何解决设计问题的
* 浏览模式的意图部分
* 研究模式怎样互相关联
* 研究目的相似的模式
* 检查重新设计的原因
* 考虑你的设计中哪些是可变的

=怎样使用设计模式=
* 大致浏览一遍模式
* 回头研究结构部分
* 看代码示例部分
* 选择模式参考者的名字, 使它们在应用上下文中有意义
* 定义类
* 定义模式中专用于应用的操作名称
* 实现执行模式中责任和协作的操作


posted @ 2008-08-10 22:01 fantasyamin 阅读(893) | 评论 (0)编辑 收藏

模式笔记二:模式的分类

一图胜千言







posted @ 2008-08-10 21:16 fantasyamin 阅读(179) | 评论 (0)编辑 收藏

模式笔记一:如何学习模式

啥叫模式? Patterns in solutions come from patterns in problems.
针对某一类经常出现的问题所采取的行之有效的解决方案
"A pattern is a solution to a problem in a context."

"Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice."(Christopher Alexander -- A Pattern Language)

模式的四个基本要素:
1. 模式名称pattern name
2. 问题problem
3. 解决方案solution
4. 效果consequences

如何描述设计模式(十大特点)
1. 意图:描述,别名
2. 动机:场景
3. 适用性: 什么情况下
4. 结构: 类图, 序列图
5. 参考者
6. 协作
7. 效果
8. 实现
9. 应用
10. 相关模式

在实践中学习是最佳的方式, 所以先要掌握每个模式的十大特点,更加重要的是在实际应用中学习, 在水中学会游泳
以迭代器模式为例, Java中有一个Iterator接口
 1 public interface Iterator
 2 {
 3   /**
 4    * Tests whether there are elements remaining in the collection. In other
 5    * words, calling <code>next()</code> will not throw an exception.
 6    *
 7    * @return true if there is at least one more element in the collection
 8    */
 9   boolean hasNext();
10 
11   /**
12    * Obtain the next element in the collection.
13    *
14    * @return the next element in the collection
15    * @throws NoSuchElementException if there are no more elements
16    */
17   Object next();
18 
19   /**
20    * Remove from the underlying collection the last element returned by next
21    * (optional operation). This method can be called only once after each
22    * call to <code>next()</code>. It does not affect what will be returned
23    * by subsequent calls to next.
24    *
25    * @throws IllegalStateException if next has not yet been called or remove
26    *         has already been called since the last call to next.
27    * @throws UnsupportedOperationException if this Iterator does not support
28    *         the remove operation.
29    */
30   void remove();
31 }
32 
假如你的类中有一些聚集关系, 那么考虑增加一个iterator方法,以实现下面这个接口
public interface Iterable
{
  
/**
   * Returns an iterator for the collection.
   *
   * 
@return an iterator.
   
*/
  Iterator iterator ();
}

返回你自己实现的ConcreteIterator类, 这个ConcreteIterator当然是实现了Iterator接口的
你会发现在遍历和迭代类中的这个成员的聚集元素时会有不同的感觉, 因为这个Iterator与实现是分离的.
你的类终归是给自己或别人使用的,在调用者的眼里, 非常简单, 管你里面是怎么实现的呢,
反正我知道你能给我一个迭代器就够了, 这里面就体现了面向接口编程的好处. 也就是按契约编程

posted @ 2008-08-10 21:07 fantasyamin 阅读(247) | 评论 (0)编辑 收藏

阻塞队列和生产者-消费者模式

自Java5以来提供的BlockingQueue是一种特殊的队列, 它 是支持两个附加操作的 Queue,这两个操作是:检索元素时等待队列变为非空,以及存储元素时等待空间变得可用。

以JDK中的例子略加改写如下

1 import java.util.concurrent.ArrayBlockingQueue;
2 import java.util.concurrent.BlockingQueue;
3
4 class Producer implements Runnable {
5     private final BlockingQueue queue;
6
7      Producer(BlockingQueue q) {
8          queue = q;
9      }
10
11     public void run() {
12         try {
13             while (true) {
14                  queue.put(produce());
15              }
16          } catch (InterruptedException ex) {
17              System.out.println("produce interrupted " + ex.getMessage());
18              Thread.currentThread().interrupt();
19             //return;
20          }
21      }
22
23      Object produce() {
24          System.out.println("produce laugh");
25         return "haha";
26      }
27 }
28
29 class Consumer implements Runnable {
30     private final BlockingQueue queue;
31
32      Consumer(BlockingQueue q) {
33          queue = q;
34      }
35
36     public void run() {
37         try {
38             while (true) {
39                  consume(queue.take());
40              }
41          } catch (InterruptedException ex) {
42              System.out.println("consume interrupted " + ex.getMessage());
43              Thread.currentThread().interrupt();
44          }
45      }
46
47     void consume(Object x) {
48          System.out.println("consume laugh "+ x);
49      }
50 }
51
52 public class BlockingQueueTest {
53     public static void main(String args[]) {
54          BlockingQueue q = new ArrayBlockingQueue(10);
55          Producer p = new Producer(q);
56          Consumer c1 = new Consumer(q);
57          Consumer c2 = new Consumer(q);
58          Thread pTh = new Thread(p);
59          pTh.start();
60          Thread cTh1 = new Thread(c1);
61          cTh1.start();
62          Thread cTh2 = new Thread(c2);
63          cTh2.start();
64         try {
65              Thread.sleep(3000);
66          }catch (Exception e) {
67             // TODO: handle exception
68          }
69          pTh.interrupt();
70          cTh1.interrupt();
71          cTh2.interrupt();
72      }
73 }
74

posted @ 2008-07-26 23:42 fantasyamin 阅读(1079) | 评论 (0)编辑 收藏

Why program fail minute

Debug中的推理:假设,预测,试验,观察,结论
1.观察错误
2.大胆假设
3.小心求证
4.假设成立则修正错误
假设推翻则重新假设

例如
1.如发现内存泄漏
2.假设A处创建的对象没有释放
3.屏蔽掉A处代码,重新编译,观察内存使用情况
4.相同条件下内存已经不再泄漏了, 则添加代码来释放A处创建的对象
反之,相同条件下内存还再泄漏,则内存泄漏仍有其他原因,重新假设
(不排除A处有错误,只有还存在错误)

推理的四种方法
1.演绎(零运行过程)
2.观察(一次运行过程)
3.归纳(多次运行过程)
4.试验(多次可控制的运行过程)

假设的依据
1.问题描述
2.程序代码
3.故障运行过程
4.参照运行过程
5.之前的假设

记录每一个假设和每一次的试验,防止遗忘,浪费精力做重复的事

在试验时注意简化,不一定要运行整个庞大的应用程序,针对自己的想法,
剥离出一小段代码单独运行,伪造假定的输出,观察是否有假定的输出

How to debug a program
# Track the problem
# Reproduce the failure
# Automate and simplify
# Find infection origins
# Focus on likely origins
# Isolate the infection chain
# Correct the defect.

==Links==
*Why program fail
http://books.google.com/books?vid=ISBN1558608664&printsec=frontcover#PPR13,M1

==Summary==

Chp1 How Failure Comes to Be

In general, a failure comes about in the four stages discussed in the following.

     1.The programmer creates a defect

     2.The defect causes an infection.

     3.The infection propagates.


     4.The infection causes a failure


     Notevery defect results in an infection, and not every infection resultsin a failure. Hence, having no failures does not imply having nodefects. This is the curse of testing, as pointed out by Dijkstra. Testing can only show the presence of defects, but never their absence.

     indeed, debugging is largely a search problem.

Chp 2 Tracking Problems

    one of the key issues of software configuration management: to be able to recreate any given configuration any time

    To separate fixes and features, use a version control system to keep fixes in branches and features in the main trunk.

    Unless you have a problem-tracking system that neatly integrates withyour test suite, I recommend keeping test outcomes separate fromproblem reports.

     problem-trackingsystems “should be usedexclusively as a place to store feedback whenyou cannot immediately modify the code.” Otherwise, you should create areproducible test case.

    Six Stages of Debugging:

     1. That can’t happen.
     2. That doesn’t happen on my machine.
     3. That shouldn’t happen.
     4. Why does that happen?
     5. Oh, I see.
     6. How did that ever work?


Chp 3 Making Program Fail

    A
program can be typically decomposed into three layers:presentation layer,functionality layer,unit layer

    The rule of thumb for testing :the friendlier an interface is to humans, the less friendly it is to automated test.

    the big advantage of testing at the functionality layers is that theresults can be easily accessed and evaluated.Of course, this requiresthe program with a clear separation between presentation andfunctionality.

    Whereas units are amongthe eldest concepts of programming, the concept of automated testing atthe unit level has seen a burst of interest only in the last few years.

    Overall, the general principle of breaking a dependence is known as the dependence inversion principle, which can be summarized as depending on abstractions rather on details.

    Test early,Test first, Test often ,Test enough

    developers are unsuited to testing their own code

Chp 4 Reproducing the problem

     Regarding problem reproduction, data as stored in files and/or databases is seldom an issue.

     To make the test reusable, one should at least aim to automate input at the higher level

    STRACE basicallyworks by diverting the calls to the operating system to wrapperfunctions that log the incoming and outgoing data.On a Linux system,all system calls use one single functionality—a specific interruptroutine that transfers control from the program to the system kernel.STRACE diverts this interrupt routine to do the logging.

    Nondeterminism introduced by thread or process schedules is among the worst problems to face in debugging.

    Some languages are more prone to Heisenbugs effect than others (inparticular, languages, where undefined behavior is part of thesemantics, such as C and C++).

    Executing on a virtual machine gives the best possibilities for recording and replaying interaction.

Chp 5 Simplifing problem

     Oncewe have reproduce a problem, we must simplify it—that is, we must findout which circumstances are not relevant for the problem and can thusbe omitted.

    Our aim is to find a minimal set of circumstances to minimize a failure-inducing configuration.

    ddmin is an instance of delta debugging—a general approach to isolate failure causes by narrowing down differences (deltas) between runs.

    Delta debugging again is an instance of adaptive testing—a series oftests in which each test depends on the results of earlier tests.

Chp 6 Scientic Debugging

     Being explicit is an important means toward understanding the problem at hand, starting with the problem statement.

     Just stating the problem in whateverway makes you rethink your assumptions—and often reveals the essential clues
to the solution.

    The idea of algorithmic debugging (also called declarative debugging) is to have a tool that guides the user along the debugging process interactively.

    algorithmic debugging works best for functional and logical programming languages

    within each iteration of the scientific method we must come up with a new hypothesis. This is the creative part of debugging: thinking about the many ways a failure could have come to be.

    Deductionis reasoning from the general to the particular. It lies at the core ofall reasoning techniques. In program analysis, deduction is used forreasoning from the program code (or other abstractions) to concrete runs
    In this book, we call any technique static analysis if it infers findings without executing the program—that is, the technique is based on deduction alone. In contrast, dynamic analysis techniques use actual executions.
    As Nethercote (2004) points out, this distinction of whether a programis executed or not may be misleading. In particular, this raises theissue of what exactly is meant by “execution.” Instead, he suggeststhat static techniques
predict approximations of a program’s future; dynamic analysis remembersapproximations of a program’s past. Because in debugging we aretypically concerned about the past, most interesting debuggingtechniques fall into
the “dynamic” categories.

    Inductionis reasoning from the particular to the general. In program analysis,induction is used to summarize multiple program runs (e.g.,a test suiteor random testing) to some abstraction that holds for all consideredprogram runs.


Chp 8 Observing Facts

    When observing state, do not interfere. Know what and when to observe, and proceed systematically.

     The"do . . . while" loop makes the macro body a single statement, forhaving code such as "if (debug) LOG(var);" work the intended way.

    Watchpoints areexpensive. Because the debugger must verify the value of the watchedexpression after each instruction, a watchpoint implies a switchbetween the debugged processes and the debugger process for eachinstruction step. This slows down program execution by a factor of1,000 or more.


Chp 9 Tracking Origins


    A common issue with observation tools(such as debuggers) is that theyexecute the program forward in time, whereas the programmer must reasonbackward in time.

    Rather than accessing the program while itis running, an omniscient debuggerfirst executes the program and records its. Once the run is complete,the omniscient debugger loads the recording and makes it available forobservation

    On average, dynamic slices are far more precise than static slices.



Chp 10 Assesrting Expectations

    The basic idea of assertions is to have the computer do the observation
   
    Overall,few techniques are as helpful for debugging as assertions, and no other technique has as many additional benefits.

    Using the GNU C runtime library (default on Linux systems), one canavoid common errors related to heap use simply by setting anenvironment variable called MALLOC_CHECK_.

    VALGRINDis built around an interpreter for x86 machinecode instructions. Itinterprets the machine instructions of the program to be debugged, andkeeps track of the used memory in so-called shadow memory.

    an assertion is not the best way of checking critical results, in that an assertion can be turned off
    an assertion is not the right way to check external conditions.

    the current trend in software development is to trade performance for runtime safety wherever possible.


Chp 11 Detecting anomalies

    code that is executed only in failing runs is more likely to contain the defect than code that is always executed.

    Anomalies are neither defects nor failure causes but can strongly correlate with either.


posted @ 2008-07-02 22:15 fantasyamin 阅读(303) | 评论 (0)编辑 收藏

隋性初始化的一种新的方式

隋性初始化的一种新的方式(java concurrency in practice)

package fanyamin.example.concurrency;

public class ResourceFactory {
    
/*
     private static Resource m_resource = null;
     public synchronized static Resource getResource() {
         if(resource == null ) {
             resource = new Resoruce();
         }
         return m_resource;
     }      
     
*/

    
private static class ResourceHoulder {
        
public static Resource m_resource = new Resource();
    }


    
public static Resource getResource() {
        
return ResourceHoulder.m_resource;
    }


}


 

posted @ 2008-06-29 18:35 fantasyamin 阅读(251) | 评论 (0)编辑 收藏

<2008年6月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

导航

统计

常用链接

留言簿(1)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜