2008年9月17日星期三






格林杜曼教育法

格 林杜曼(GLENN DOMAN)博士,于1940年开始对人类潜能的研究,1955年成立人类潜能开发学会(The Institutes for the
Achievement of Human
Potential),60年代开始从事早期脑损伤儿童的治疗研究,所发明的DOMAN教学法早期主要用于脑损伤儿童的治疗,后来发现对健康儿童也有很好的促进效果。Doman在巴西、意大利、法国、西班牙等许多国家都已经开展工作多年,日本Sony公司和美国Doman研究所合作了几十年,他足迹遍及
100多个国家,曾获巴西、英国、爱尔兰、阿根廷、秘鲁、日本等多国的赠勋。代表著作:How to teach your baby math, How to
give your baby encyclopedic knowledge, How to teach your baby read, How to teach
your baby to be physically
superb.
中文繁体版本香港台湾地区有卖。书名:《如何教宝宝数学》、《如何教宝宝百科知识》、《如何教宝宝阅读》、《如何使宝宝身体强健》、《如何让你的宝宝更聪明》等。
这些书籍在VeryCD发布上传的链接为
http://board.VeryCD.com/t418390.html
VeryCD上另外一份中文《DOMAN教学法配套镜像光盘》10CD下载链接为http://lib.VeryCD.com/2006/06/01/0000105155.html

这里上传的是原版杜曼的教学光盘的视频剪辑格式文件。语言为英文。清晰度一般,但是观看完全没有问题。
1.
如何教你的宝宝百科知识
2.
如何让你的宝宝身强体健1
3.如何让你的宝宝身强体健2
4.如何教你的宝宝数学
5.如何教你的宝宝阅读


Doman的主要思想

我们的目的﹕

养育出智能高﹑能力强又快乐的孩子﹐并由此创作出一个非常优雅﹑理性而和谐的世界。


小婴儿拥有天赋的佳礼------人类的大脑皮质。唯一的问题是为人父母者能够提供一个怎样的环境来让这个大脑皮质生长发育。

每个父母都有能力去培育宝宝体内那颗天才的种子﹐且有能力将宝宝的智能提高到力所能及或所希望的程度。
以爱与诚心教宝宝﹐宝宝可以学会任何事情。

人类的特质之一便是能将宝宝置于自己落后的地方再起步﹐这全是因为我们有神奇而独特的人类的大脑皮质。
我们应以既有的一切而尽其所能﹐而我也相信我们可以做到。


小宝宝认为学习是一种生存的技巧


小宝宝生来就具有高度学习的热忱﹐他们什么都想学﹐而且是立刻去学。小宝宝认为学习是最棒的事﹐而一般却认为﹐小宝宝最初的6年﹐应该用来玩耍。

小宝宝认为学习是一种生存的技巧﹐那的确是。学习是一种生存的技巧。

每一万个鳟鱼卵中只有一个能长成﹐每四十个龟卵中只有一个能存活。小动物的尸体是无言的见证------学习是一种生存的技巧。

这个法则与人类更甚------每个宝宝都有与生俱来的学习本能。

大自然有保障物种与个体生存的特殊秘诀。它以迷人而愉快的技巧使我们的种系能存续﹐当一个宝宝诞生时﹐它又施以技巧来保障这孩子的存活。它使他一出生便相信﹐一直学习是全世界最棒的事﹐除非我们使他不再相信或不让他继续相信。

几乎每个人的一生在其六岁前就已经决定了。学习的能力与年龄成反比。年龄越大﹐越难以接受事实的本质。反之﹐年龄越轻﹐则越容易。

教5岁大的孩子比教6岁大的孩子容易。

教4岁大的孩子比教5岁大的孩子容易。

教半岁大的孩子比教1岁大的孩子容易。

年纪越轻﹐就越容易接受事物原来的面貌并一直保存它。

年纪越大﹐就越有智慧﹐这是成年人超越孩子的地方。

一旦出生﹐接受事实的能力便如宇宙飞船发射般急速成长﹐而且象宇宙飞船一样的﹐当其速度达到顶峰便不再增加﹐而后便与地平线平行了。6岁左右时﹐这项能力便可说是终止了﹐相反的﹐到了6岁﹐智慧才缓慢地开始。

学习的能力如火箭般升起﹐但也很快地下降﹐此时智慧才刚起步﹐这两者在6岁时汇合。就在此时﹐小孩能轻易学得信息的能力已经结束﹐而大脑的发育也已经几乎完全﹐
他的将来如何已经决定了。可是他的智慧才刚要开始发展﹐他的智慧将随着年龄的增长而逐年增加。

重要的是﹐在生命的前6年中﹐他学会了什么﹐学到了多少﹖每一样都会影响他的一生。

以听的方式﹐教宝宝语言﹐只有三个条件﹕大声﹑清晰﹑重复。因为宝宝听觉和记忆系统还没发育好。当妈妈大声重复地说﹕“来妈妈这里﹐来妈妈这里”﹐当宝宝向妈妈走去时﹐这便代表听觉系统的成长与成熟。这是神经生理的自然发展过程。

由眼睛学习讯息的过程同样关乎神经生理﹐过程与听觉系统一样﹐有三个条件﹕大字﹑清楚﹑重复。小宝宝的视觉系统发育速度远慢于其听觉系统。但视觉系统如听觉系统般﹐不用则退。你越不用它﹐它越迟钝。视觉系统构成大脑的后半部。“不用则退”对任一系统都重要。

小孩的学习速度﹐快得超乎我们的想象而令人吃惊。人脑中有一项已建立的构架﹐用简单的方式说﹐就是﹕教导幼儿知识的真象﹐他便会由他操作的过程中发现其中的规则。

宝宝建立错误文法的方式可说明这件事。教导幼儿规则﹐他无法自行发现事实。

成人喜欢将信息分成两类﹕具体的﹐与摘要的。具体的﹐就是我们能了解及容易解释的。摘要的﹐则是我们无法理解﹐也不知如何解释的。

小孩有极大的能力去从我们所教他的事实中找出规律。但当我们教小孩一大堆摘要的规定时﹐他是无法发现事实的。

关于科学的定义﹐其中一则是﹕“一种能有系统的展示操作定律的知识。”这是对小孩如何学习的步骤的最佳说明。首先他们要吸收一大堆事实﹐然后他们用自己的办法去归纳整理出一套规则。极为好奇﹐是所有真正的天才和小孩所共有的特质。

3岁前﹐孩子学到的事实﹐比三岁后学到的多得多。6岁前的学习能力是6岁后的三倍。
学习并非教育的同义词。教育始于6岁﹐学习始于出生。

小孩是绝佳的学习者﹐唯一限制他们的﹐是他们可接触到多少材料及如何给予他们。生命中的前6年是天才的起源。生命中的前6年也是大脑生长的关键期。想想头围变化的奇迹。

人类最初受精时﹐是没有脑子的﹐只不过是一个单细胞的受精卵。

九个月后﹐新生儿出生﹐头围约35公分。

两岁半时﹐头围增为50公分。

大脑生长及停下来不变的过程﹐真是何其的戏剧化啊﹗

9个月------30公分

21个月------多15公分。

231个月------多5公分。

在6岁前﹐使幼儿成为天才﹐是很容易的事。人类生命的前6年的重要性﹐是无法衡量的。如果一个孩子﹐6年中一直被关着不与外界接触﹐他6岁时﹐你将见到一个白痴。如果你没有把孩子关起来﹐但却象对待一个白痴似的忽略他﹐那他的情形将比白痴好一点而已。

如果你对他就象对待一般孩子那样﹐那他就会象个一般孩子。如果你确实了解大脑生长的原则﹐那么在孩子生命中最重要的6年里﹐你一定会用另一种完全不同的态度来对待他。

这将端视你是否持续采用这种组织过的方式教他阅读﹑数学和百科知识。

童年是那么有趣﹐它使你每个日子都那么有价值。给孩子能持续一生的对学习的热爱。因为每个孩子一出生﹐便拥有学习的狂热﹐我们所要做的﹐就是不要压抑这股狂热罢了。

如果你想让宝宝不喜欢某件事﹐只要想尽办法指出他的弱点与错处便行了。如果你想让宝宝乐于去做某件事﹐并一再表现给你看﹐他能做得有多好﹐那么只要告诉他﹐什么事他做得很好便行了。

如果你要毁了他所有的动机﹐则只需一再测试他﹐并且告诉他﹐还差多少分﹐才是满分。
如果你要提高他的动机﹐则找出他做得对的事﹐并热诚地告诉他你的想法。

告诉你的宝宝﹐他有多棒﹐以及你有多爱他﹐常常告诉他这些话。

2008年5月31日星期六

The Observer Pattern for Delphi
Filed under: Design Patterns — Joanna Carter @ 3:29 pm

Introduction

When we use Delphi to design forms and data modules, every time we place a component on the designer, several things change: the form now shows an appropriate representation of the component, the object inspector changes to show the properties of the component and, if we press Alt-F12, we see the .DFM file now contains information about the component. Whether this behaviour was modelled correctly on the Observer pattern or not, the result is that several ‘interested parties’ got to know about a change in the content of the project that we are working on.

If you read the GoF Design Patterns book, you will find much discussion on the semantics and structure of the Observer pattern. Do we want to have one subject and many observers; do we want to have many subjects and one observer; or do we want many observers to keep track of many subjects? The answer to these questions will depend to a great extent on the application that you find yourself developing. Delphi, for example may be seen as using all of these variants in some part of the IDE.

In the same book, you will see that in order to implement the Observer pattern to implement a Digital Clock observer that relates to a Clock Timer subject, use is made of multiple inheritance. But Delphi does not support multiple inheritance… "No, not that old chestnut again!", I hear you cry, "Surely what we need in Delphi v10 is multiple inheritance?". Well, yes and no.

There are two primary mechanisms for circumventing a lack of multiple inheritance: Composition and Interfaces.
Abstract Concepts

Let us start by looking at the abstract concepts of Observers and Subjects as discussed in Gamma’s book:



IObserver

procedure Update(Subject: IInterface);

ISubject
procedure Attach(Observer: IObserver);
procedure Detach(Observer: IObserver);
procedure Notify;


As you can see the basic idea of an Observer is that it can be told when the Subject has changed; this is achieved when the Subject calls the Observer.Update method and passes itself as the Subject parameter. The ISubject consists of methods for attaching and detaching IObservers as well as a Notify method, which iterates through any Observers that are attached.
Composition

If you are not comfortable with using interfaces, which is the simplest way of implementing the Observer pattern, then you need to use Composition to supply the necessary additional functionality to existing classes. Composition involves the placing of an instance of a class that implements a desired behaviour inside a derivative of the class that needs to be extended.



TObserver = class

public

procedure Update(const Subject: TObject); virtual; abstract;

end;

TSubject = class
private
fController: TObject;
fObservers: TObjectList;
public
constructor Create(const Controller: TObject);
procedure Attach(const Observer: TObserver);
procedure Detach(const Observer: TObserver);
procedure Notify;
end;


We start off by writing an abstract class for the Observer that provides a method called Update that can be overridden, depending on the class that is to be an Observer. The Subject class can take care of managing the list of Observers and the broadcasting of updates to them.



constructor TSubject.Create(const Controller: TObject);

begin

inherited Create;

fController := Controller;

end;

procedure TSubject.Attach(const Observer: TObserver);
begin
if fObservers = nil then
fObservers := TObjectList.Create;
if fObservers.IndexOf(Observer) < 0 then
fObservers.Add(Observer);
end;

procedure TSubject.Detach(const Observer: TObserver);
begin
if fObservers <> nil then
begin
fObservers.Remove(Observer);
if fObservers.Count = 0 then
begin
fObservers.Free;
fObservers := nil;
end;
end;
end;

procedure TSubject.Notify;
var
i: Integer;
begin
if fObservers <> nil then
for i := 0 to Pred(fObservers.Count) do
TObserver(fObservers[i]).Update(fController);
end;


The constructor for the TSubject class takes a TObject as a ‘Controller’ parameter and this object is retained for use as the ‘real’ Subject to be sent to each of the Observers; otherwise all the Observers will see is a TSubject and not the actual subject class.
Watching the Clock

The GoF book uses the example of a digital clock to demonstrate the principles of the Observer pattern and we will use that same example here.

Let’s start by designing a simple class to represent the Clock mechanism:



TClockTimer = class

private

fTimer: TTimer;

fInternalTime: TDateTime;

fSubject: TSubject;

procedure Tick(Sender: TObject);

public

constructor Create;

destructor Destroy; override;

function GetTime: TDateTime;

property Subject: TSubject

read fSubject;

end;


This particular clock uses a TTimer to keep its own time and for the purpose of this example will update itself every second.

The signature of the Tick method is that of a TNotifyEvent in order to simplify the handling of the timer interval. In the Tick Method, I set an internal variable to the current time to avoid any difference in time portrayed between calls to GetTime by the attached Observers.



constructor TClockTimer.Create;

begin

inherited Create;

fTimer := TTimer.Create(nil);

fTimer.Interval := 1000;

fTimer.OnTimer := Tick;

fTimer.Enabled := True;

fSubject := TSubject.Create(self);

end;

destructor TClockTimer.Destroy;
begin
fSubject.Free;
fTimer.Enabled := False;
fTimer.Free;
inherited Destroy;
end;

function TClockTimer.GetTime: TDateTime;
begin
Result := fInternalTime;
end;

procedure TClockTimer.Tick(Sender: TObject);
begin
fInternalTime := Now;
fSubject.Notify;
end;


Notice the inclusion of a private TSubject field that will allow us to notify the list of Observers. The constructor not only creates the instance of TSubject, it also passes itself to the Subject constructor, so that the Subject can have a TClockTimer to pass to the Observers during the Notify method.

Every time the TTimer.OnTimer event fires, the internal time field is updated to the current time and then the Subject’s Notify event is called.
Putting on a Face

Now we have a clock mechanism, we also need a face for our clock; a way of displaying the time provided by the mechanism.



TDigitalClock = class;

TClockObserver = class(TObserver)
private
fDisplay: TDigitalClock;
public
constructor Create(const Display: TDigitalClock);
procedure Update(const Subject: TObject); override;
end;

TDigitalClock = class(TPanel)
private
fObserver: TClockObserver;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Observer: TClockObserver
read fObserver;
procedure ObserverUpdate(const Subject: TClockTimer);
end;


As we have said before, Delphi does not support multiple inheritance and so, to be able to derive our Digital Clock face from TPanel we also need to use composition to mix a TObserver class with the TDigitalClock class. Note also that we have to ensure that the Update method of TPanel is not suitable for responding to calls to TObserver.Update, therefore we have called our method ObserverUpdate to avoid confusion.

Just as we had to pass in the Clock Timer to the Subject, we also have to pass the Digital Clock to the Observer. The Update method of TClockObserver will call ObserverUpdate in TDigitalClock to allow the Text property of the TPanel to be updated.



constructor TClockObserver.Create(const Display: TDigitalClock);

begin

inherited Create;

fDisplay := Display;

end;

procedure TClockObserver.Update(const Subject: TObject);
begin
if (Subject is TClockTimer) then
fDisplay.ObserverUpdate(TClockTimer(Subject));
end;


The Clock Observer class derives from TObserver and overrides the Update method to check if the Subject being passed is indeed a TClockTimer and then passes that Clock Timer to the ObserverUpdate method of the Digital Clock.



constructor TDigitalClock.Create(AOwner: TComponent);

begin

inherited Create(AOwner);

fObserver := TClockObserver.Create(self);

end;

destructor TDigitalClock.Destroy;
begin
fObserver.Free;
inherited Destroy;
end;

procedure TDigitalClock.ObserverUpdate(const Subject: TClockTimer);
begin
Text := FormatDateTime(’tt’, Subject.GetTime);
end;


All that is left for the display class to do is to respond to the update by setting the Text property to the value provided by the Clock Timer subject.
Observer Interfaces

Instead of using Composition to circumvent the lack of multiple inheritance, we can also use Interfaces in a way that allows us to support the concept of deriving a class that ‘inherits’ the behaviour of more than one type.

When describing multiple inheritance, the example of an amphibious vehicle is often used. But the concept of an amphibious vehicle does not truly represent an object that is truly a car and truly a boat; surely it is, more accurately, a vehicle that can behave like a car or like a boat. What interfaces allow us to do is to design classes that support multiple behaviours. So let us go on to look at how we can simplify the Observer pattern using interfaces.



IObserver = interface

[’{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}’]

procedure Update(Subject: IInterface);

end;

ISubject = interface
[’{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}’]
procedure Attach(Observer: IObserver);
procedure Detach(Observer: IObserver);
procedure Notify;
end;


In the above example using Composition, we had to write an abstract class called TObserver that had just the one method, Update, but if you look at these interface declarations, you actually have the equivalent of an abstract class. Essentially an interface is almost the same as an abstract class with a few more features like reference counting and the ability to be mixed with other interfaces in a class.

As with the non-interface method of implementing the Observer pattern, we can implement the ISubject interface once and for all and aggregate an instance of TSubject into our Subject class to avoid rewriting the same code over and over again.



TSubject = class(TInterfacedObject, ISubject)

private

fController: Pointer;

fObservers: IInterfaceList;

procedure Attach(Observer: IObserver);

procedure Detach(Observer: IObserver);

procedure Notify;

public

constructor Create(const Controller: IInterface);

end;


Gamma uses a template List container class to maintain the list of Observers, but as we are not using C++ we will use a IInterfaceList as this is the correct way to store lists of references to interfaces. So let’s go on to look at the implementation for this base TSubject class:



constructor TSubject.Create(const Controller: IInterface);

begin

inherited Create;

fController := Pointer(Controller);

end;

procedure TSubject.Attach(AObserver: IObserver);
begin
if fObservers = nil then
fObservers := TInterfaceList.Create;
fObservers.Add(AObserver);
Notify;
end;

procedure TSubject.Detach(AObserver: IObserver);
begin
if fObservers <> nil then
begin
fObservers.Remove(AObserver);
if fObservers.Count = 0 then
fObservers := nil;
end;
end;

procedure TSubject.Notify;
var
i: Integer;
begin
if fObservers <> nil then
for i := 0 to Pred(fObservers.Count) do
(fObservers[i]. as IObserver).Update(IInterface (fController));
end;


The constructor takes an IInterface reference to the aggregating object (in our example the Clock Timer) and stores it in a Pointer field; this ‘weak reference’ technique avoids reference-counting problems that could cause a memory leak due to the mutual references between the TSubject and its aggregating class.

The Attach and Detach methods are fairly straightforward, but I will go into a little more detail with the Notify method. This method traverses the list of Observers that are attached to the Subject and calls the Update method for each observer that it finds. The fController field that is the real subject (Clock Timer) has to be cast back to an IInterface in order to be passed to the Update method of the Observer interface.
A Universal Ticker

Here is the interface definition for the ‘mechanism’ of our clock:



IClockTimer = interface

[’{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}’]

function GetTime: TDateTime;

end;


The declaration of the TClockTimer implementing class is slightly different from the non-interface version. Instead of deriving from TObject, it derives from TInterfacedObject in order to give us a ready-made implementation of IInterface and then also implements the Clock Timer and Subject interfaces.



TClockTimer = class(TInterfacedObject, IClockTimer, ISubject)

private

fTimer: TTimer;

fInternalTime: TDateTime;

fSubject: ISubject;

function GetTime: TDateTime;

procedure Tick(Sender: TObject);

property Subject: ISubject

read fSubject

implements ISubject;

public

constructor Create;

end;


The main differences are: all methods (apart from the constructor) and properties are now private because they will only be accessed through the supported Interfaces. The Subject property is declared with the implements directive so that any attempt to reference the ISubject interface will be redirected to the embedded TSubject instance.



destructor TClockTimer.Destroy;

begin

fTimer.Enabled := False;

fTimer.Free;

inherited Destroy;

end;


The only difference in the code required for the interface version of this class is the omission of the call to fSubject. Free; this is not necessary or possible, as it will automatically fall out of scope when the Clock Timer is destroyed and Free is not a method of IInterface.
Widgets and Other Furry Animals

In Gamma’s book, the Digital Clock class is derived from a Widget class and from the abstract Observer class previously discussed. As we are not able to use multiple inheritance, we are going to have to find another way of implementing a Widget that is also an Observer. For a very simple demonstration component that you can put on a form, I decided that my ‘Widget’ would be a TPanel. Here is the class declaration:



TDigitalClock = class(TPanel, IObserver)

private

procedure IObserver.Update = ObserverUpdate;

procedure ObserverUpdate(const Subject: IInterface);

end;

procedure TDigitalClock.ObserverUpdate(const Subject: IInterface);
var
Obj: IClockTimer;
begin
Subject.QueryInterface(IClockTimer, Obj);
if Obj <> nil then
Caption := FormatDateTime(’tt’, Obj.GetTime);
end;


Because TPanel already has an Update method that is unsuitable for our purposes, we have to redirect the IObserver.Update method to another method, which I have called ObserverUpdate.

In ObserverUpdate you will see that a check is made to ensure that the Subject being passed in is really a Clock Timer and then, if it is a valid subject, the visual representation on the ‘Widget’ is updated using the GetTime method of the Subject.

After installing this component into the VCL, the only other code needed to get a demonstration going is to declare a private variable of type IClockTimer on a test form then add a button and the following event handlers:



procedure TForm1.FormCreate(Sender: TObject);

begin

fClockTimer := TClockTimer.Create;

end;

procedure TForm1.Button1Click(Sender: TObject);

begin

(DigitalClock1 as ISubject).Attach(fClockTimer as IObserver);

end;


Any number of Digital Clocks can be placed on the form and attached to the Clock Timer and they will all be notified and kept up to date every second.

2008年5月30日星期五

C#设计模式(3)

http://www.cnblogs.com/zhenyulu/articles/36068.html

三、 依赖倒置原则(DIP)

依赖倒置(Dependence Inversion Principle)原则讲的是:要依赖于抽象,不要依赖于具体。

简单的说,依赖倒置原则要求客户端依赖于抽象耦合。原则表述:

抽象不应当依赖于细节;细节应当依赖于抽象;
要针对接口编程,不针对实现编程。

反面例子:



缺点:耦合太紧密,Light发生变化将影响ToggleSwitch。

解决办法一:
将Light作成Abstract,然后具体类继承自Light。

优点:ToggleSwitch依赖于抽象类Light,具有更高的稳定性,而BulbLight与TubeLight继承自Light,可以根据"开放-封闭"原则进行扩展。只要Light不发生变化,BulbLight与TubeLight的变化就不会波及ToggleSwitch。

缺点:如果用ToggleSwitch控制一台电视就很困难了。总不能让TV继承自Light吧。

解决方法二:

优点:更为通用、更为稳定。

结论:
使用传统过程化程序设计所创建的依赖关系,策略依赖于细节,这是糟糕的,因为策略受到细节改变的影响。依赖倒置原则使细节和策略都依赖于抽象,抽象的稳定性决定了系统的稳定性。

四、 接口隔离原则(ISP)

接口隔离原则(Interface Segregation Principle)讲的是:使用多个专门的接口比使用单一的总接口总要好。换而言之,从一个客户类的角度来讲:一个类对另外一个类的依赖性应当是建立在最小接口上的。

过于臃肿的接口是对接口的污染。不应该强迫客户依赖于它们不用的方法。

My object-oriented umbrella(摘自Design Patterns Explained)

Let me tell you about my great umbrella. It is large enough to get into! In fact, three or four other people can get in it with me. While we are in it, staying out of the rain, I can move it from one place to another. It has a stereo system to keep me entertained while I stay dry. Amazingly enough, it can also condition the air to make it warmer or colder. It is one cool umbrella.

My umbrella is convenient. It sits there waiting for me. It has wheels on it so that I do not have to carry it around. I don't even have to push it because it can propel itself. Sometimes, I will open the top of my umbrella to let in the sun. (Why I am using my umbrella when it is sunny outside is beyond me!)

In Seattle, there are hundreds of thousands of these umbrellas in all kinds of colors. Most people call them cars.

实现方法:
1、 使用委托分离接口
2、 使用多重继承分离接口

五、 合成/聚合复用原则(CARP)

合成/聚合复用原则(Composite/Aggregate Reuse Principle或CARP)经常又叫做合成复用原则(Composite Reuse Principle或CRP),就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新对象通过向这些对象的委派达到复用已有功能的目的。

简而言之,要尽量使用合成/聚合,尽量不要使用继承。

o Design to interfaces.
o Favor composition over inheritance.
o Find what varies and encapsulate it.
(摘自:Design Patterns Explained)

区分"Has-A"与"Is-A"

"Is-A"是严格的分类学意义上定义,意思是一个类是另一个类的"一种"。而"Has-A"则不同,它表示某一个角色具有某一项责任。

导致错误的使用继承而不是合成/聚合的一个常见的原因是错误的把"Has-A"当作"Is-A"。

例如:

实际上,雇员、经理、学生描述的是一种角色,比如一个人是"经理"必然是"雇员",另外一个人可能是"学生雇员",在上面的设计中,一个人无法同时拥有多个角色,是"雇员"就不能再是"学生"了,这显然是不合理的。

错误源于把"角色"的等级结构与"人"的等级结构混淆起来,误把"Has-A"当作"Is-A"。解决办法:

六、 迪米特法则(LoD)

迪米特法则(Law of Demeter或简写LoD)又叫最少知识原则(Least Knowledge Principle或简写为LKP),也就是说,一个对象应当对其它对象有尽可能少的了解。

其它表述:
只与你直接的朋友们通信
不要跟"陌生人"说话
每一个软件单位对其它的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。

迪米特法则与设计模式
Facade模式、Mediator模式

使民无知
《老子》第三章曰:"是以圣人之治,虚其心,实其腹,弱其志,常使民无知无欲。"使被"统治"的对象"愚昧"化,处于"无知"的状态,可以使"统治"的成本降低。
所谓"最少知识"原则,实际上便是老子的"使民无知"的统治之术。

不相往来
《老子》云:"小国寡民……邻国相望,鸡犬之声相闻,民至老死,不相往来。"将被统治的对象隔离开来,使它们没有直接的通信,可以达到分化瓦解,继而分而治之的效果。迪米特法则与老子的"小国寡民"的统治之术不谋而合。



参考文献:
阎宏,《Java与模式》,电子工业出版社
[美]James W. Cooper,《C#设计模式》,电子工业出版社
[美]Alan Shalloway James R. Trott,《Design Patterns Explained》,中国电力出版社
[美]Robert C. Martin,《敏捷软件开发-原则、模式与实践》,清华大学出版社
[美]Don Box, Chris Sells,《.NET本质论 第1卷:公共语言运行库》,中国电力出版社
http://www.dofactory.com/Patterns/Patterns.aspx

C#设计模式(2)

http://www.cnblogs.com/zhenyulu/articles/36061.html

《人月神话》焦油坑、没有银弹

* 软件腐化的原因:

问题所在 设计目标
----------------------------------------------------------------------------
过于僵硬 可扩展性(新性能可以很容易加入系统)
过于脆弱 灵活性(修改不会波及其它)
复用率低
粘度过高 可插入性(新功能容易加入系统(气囊加入方向盘))

* 提高系统可复用性的几点原则:
传统复用:
1. 代码的粘帖复用
2. 算法的复用
3. 数据结构的复用

* 可维护性与可复用性并不完全一致

* 对可维护性的支持:


一、 "开放-封闭"原则(OCP)

Open-Closed Principle原则讲的是:一个软件实体应当对扩展开放,对修改关闭。

优点:
通过扩展已有软件系统,可以提供新的行为,以满足对软件的新的需求,使变化中的软件有一定的适应性和灵活性。
已有软件模块,特别是最重要的抽象层模块不能再修改,这使变化中的软件系统有一定的稳定性和延续性。

例子:玉帝招安美猴王
当年大闹天宫便是美猴王对玉帝的新挑战。美猴王说:"'皇帝轮流做,明年到我家。'只教他搬出去,将天宫让于我!"对于这项挑战,太白金星给玉皇大帝提出的建议是:"降一道招安圣旨,宣上界来…,一则不劳师动众,二则收仙有道也。"

换而言之,不劳师动众、不破坏天规便是"闭",收仙有道便是"开"。招安之道便是玉帝天庭的"开放-封闭"原则。

招安之法的关键便是不允许更改现有的天庭秩序,但允许将妖猴纳入现有秩序中,从而扩展了这一秩序。用面向对象的语言来讲,不允许更改的是系统的抽象层,而允许更改的是系统的实现层。


二、 里氏代换原则(LSP)

Liskov Substitution Principle(里氏代换原则):子类型(subtype)必须能够替换它们的基类型。

白马、黑马

反过来的代换不成立
《墨子·小取》说:"娣,美人也,爱娣,非爱美人也……"娣便是妹妹,哥哥喜爱妹妹,是因为两人是兄妹关系,而不是因为妹妹是个美人。因此,喜爱妹妹不等同于喜爱美人。用面向对象语言描述,美人是基类,妹妹是美人的子类。哥哥作为一个有"喜爱()"方法,接受妹妹作为参数。那么,这个"喜爱()"方法一般不能接受美人的实例。

一个违反LSP的简单例子(长方形和正方形)

public class Rectangle
{
private long width;
private long height;

public void setWidth(long width)
{
this.width = width;
}

public long getWidth()
{
return this.width;
}

public void setHeight(long height)
{
this.height = height;
}

public long getHeight()
{
return this.height;
}

}


public class Square
{
private long side;

public void setSide(long side)
{
this.side = side;
}


public long getSide()
{
return side;
}

}


正方形不可以做长方形的子类

using System;

public class Rectangle
{
private long width;
private long height;

public void setWidth(long width)
{
this.width = width;
}

public long getWidth()
{
return this.width;
}

public void setHeight(long height)
{
this.height = height;
}

public long getHeight()
{
return this.height;
}

}


public class Square : Rectangle
{
private long side;

public void setWidth(long width)
{
setSide(width);
}


public long getWidth()
{
return getSide();
}


public void setHeight(long height)
{
setSide(height);
}


public long getHeight()
{
return getSide();
}


public long getSide()
{
return side;
}


public void setSide(long side)
{
this.side = side;
}

}


public class SmartTest
{
public void resize(Rectangle r)
{
while (r.getHeight() >= r.getWidth() )
{
r.setWidth(r.getWidth()
+ 1);
}

}

}


在执行SmartTest的resize方法时,如果传入的是长方形对象,当高度大于宽度时,会自动增加宽度直到超出高度。但是如果传入的是正方形对象,则会陷入死循环。

代码重构

public interface Quadrangle
{
public long getWidth();
public long getHeight();
}


public class Rectangle : Quadrangle
{
private long width;
private long height;

public void setWidth(long width)
{
this.width = width;
}

public long getWidth()
{
return this.width;
}

public void setHeight(long height)
{
this.height = height;
}

public long getHeight()
{
return this.height;
}

}


public class Square : Quadrangle
{
private long side;

public void setSide(long side)
{
this.side = side;
}


public long getSide()
{
return side;
}


public long getWidth()
{
return getSide();
}


public long getHeight()
{
return getSide();
}

}




参考文献:

阎宏,《Java与模式》,电子工业出版社

[]James W. Cooper,《C#设计模式》,电子工业出版社

[]Alan Shalloway James R. Trott,《Design Patterns Explained》,中国电力出版社

[]Robert C. Martin,《敏捷软件开发-原则、模式与实践》,清华大学出版社

[]Don Box, Chris Sells,《.NET本质论 1卷:公共语言运行库》,中国电力出版社
http://www.dofactory.com/Patterns/Patterns.aspx

指定目录的图片2值化

```python # -*- coding: utf-8 -*- """指定目录的图片,自适应2值化 """ import os from PIL import Image import numpy as np imp...