Showing posts with label SOLID. Show all posts
Showing posts with label SOLID. Show all posts

Saturday, February 27, 2016

SOLID - Summary



A function should do one, and only one, thing. We use that principle when we are refactoring large functions into smaller functions; we use it at the lowest levels

A module should have one, and only one, reason to change.
A module should be responsible to one, and only one, actor.

A software artifact should be open for extension but closed for modification.

THE SQUARE/RECTANGLE PROBLEM

ISP: THE INTERFACE SEGREGATION PRINCIPLE
it is harmful to depend on modules that contain more than you need.

DIP: THE DEPENDENCY INVERSION PRINCIPLE
Source code dependencies refer only to abstractions, not to concretions.

interfaces are less volatile than implementations.

Which classes belong in which components?
THE REUSE/RELEASE EQUIVALENCE PRINCIPLE
THE COMMON CLOSURE PRINCIPLE
Gather into components those classes that change for the same reasons and at the same times. Separate into different components those classes that change at different times and for different reasons.

THE COMMON REUSE PRINCIPLE
Don’t force users of a component to depend on things they don’t need.

Orthogonality
Two or more things are orthogonal if
changes in one do not affect any of the others. In a well-designed system, the database code
will be orthogonal to the user interface: you can change the interface without affecting the
database, and swap databases without changing the interface.

Every Piece Of Data Should Have One Representation
Functions Should Do One Thing

Use Dummy Data
If It’s Taking Too Long You Are Probably Making a Mistake

Do Things The Best Way The First Time
Follow Conventions

PyCharm

"Good design adds value faster than it adds cost."
The Four Pillars of Object-oriented
inheritance, polymorphism, abstraction and encapsulation

SRP AND THE DECORATOR PATTERN
The Composite pattern is a specialization of the Decorator pattern
The Composite pattern’s purpose is to allow you to treat many instances of an interface as if they were just one instance. Therefore, clients can accept just one instance of an interface, but they can be implicitly provided with many instances, without requiring the client to change

Predicate decorators
Branching decorators

The open/closed principle
Software entities should be open for extension, but closed for modification.
A more permissive exception to the “closed for modification” rule is that any change to existing code is allowed as long as it does not also require a change to any client of that code.

Classes that honor the OCP should be open to extension by containing defined extension points where future functionality can hook into the existing code and provide new behaviors.

“Design for inheritance or prohibit it”
Identify points of predicted variation and create a stable interface around them.

A stable interface
Just enough adaptability
The predicted variation guideline states that you should be explicit in what you allow and disallow to be extended. The speculative generality guideline states that you should beware of trying to preempt how a class might apply to a general problem, lest you create a leaky abstraction.


http://blog.jetbrains.com/upsource/2015/08/31/what-to-look-for-in-a-code-review-solid-principles-2/
Single Responsibility Principle (SRP)
There should never be more than one reason for a class to change.
This can sometimes be hard to spot from a single code review. By definition, the author is (or should be) applying a single reason to change the code base – a bug fix, a new feature, a focussed refactoring.
You want to look at which methods in a class are likely to change at the same time, and which clusters of methods are unlikely to ever be changed by a change to the other methods. For example:
Single Responsibility Principle
This side-by-side diff from Upsource shows that a new piece of functionality has been added toTweetMonitor, the ability to draw the top ten Tweeters in a leaderboard on some sort of user interface. While this seems reasonable because it uses the data being gathered by theonMessage method, there are indications that this violates SRP. The onMessageand getTweetMessageFromFullTweet methods are both about receiving and parsing a Twitter message, whereas draw is all about reorganising that data for displaying on a UI.
The reviewer should flag these two responsibilities, and then work out with the author a better way of separating these features: perhaps by moving the Twitter string parsing into a different class; or by creating a different class that’s responsible for rendering the leaderboard.
Open-Closed Principle (OCP)
Software entities should be open for extension, but closed for modification.
As a reviewer, you might see indications that this principle is being violated if you see a series of if statements checking for things of a particular type:
Open-Closed Principle
If you were reviewing the code above, it should be clear to you that when a new Event type is added into the system, the creator of the new event type is probably going to have to add another else to this method to deal with the new event type.
It would be better to use polymorphism to remove this if:
Open-Closed Principle
Open-Closed Principle
As always, there’s more than one solution to this problem, but the key will be removing the complex if/else and the instanceof checks.
Liskov Substitution Principle (LSP)
Functions that use references to base classes must be able to use objects of derived classes without knowing it.
One easy way to spot violations of this principle is to look for explicit casting. If you have to cast a object to some type, you are not using the base class without knowledge of the derived classes.
More subtle violations can be found when checking:
Imagine, for example, we have an abstract Order with a number of subclasses – BookOrder,ElectronicsOrder and so on. The placeOrder method could take a Warehouse, and could use this to change the inventory levels of the physical items in the warehouse:
Liskov Substitution Principle
Now imagine we introduce the idea of electronic gift cards, which simply add balance to a wallet but do not require physical inventory. If implemented as a GiftCardOrder, theplaceOrder method would not have to use the warehouse parameter:
CR5-LSP1
This might seem like a logical use of inheritance, but in fact you could argue that code that uses GiftCardOrder could expect similar behaviour from this class as the other classes, i.e. you could expect this to pass for all subtypes:
CR5-LSP2
But this will not pass, as GiftCardOrders have a different type of order behaviour. If you’re reviewing this sort of code, question the use of inheritance here – maybe the order behaviour can be plugged in using composition instead of inheritance.
Interface Segregation Principle (ISP)
Many client specific interfaces are better than one general purpose interface.
Some code that violates this principle will be easy to identify due to having interfaces with a lot of methods on.  This principle compliments SRP, as you may see that an interface with many methods is actually responsible for more than one area of functionality.
But sometimes even an interface with just two methods could be split into two interfaces:
CR5-LSP3
In this example, given that there are times when the decode method might not be needed, and also that a codec can probably be treated as either an encoder or a decoder depending upon where it’s used, it may be better to split the SimpleCodec interface into an Encoder and aDecoder. Some classes may choose to implement both, but it will not be necessary for implementations to override methods they do not need, or for classes that only need anEncoder to be aware that their Encoder instance also implements decode.
Dependency Inversion Principle (DIP)
Depend upon Abstractions. Do not depend upon concretions.
This code is dependent on a lot of specific implementation details: JDBC as a connection to a (relational) database; database-specific SQL; knowledge of the database structure; and so on. This does belong somewhere in your system, but not here where there are other methods that don’t need to know about databases. Better to extract a DAO or use the Repository pattern, and inject the DAO or repository into this service.
https://xmruibi.gitbooks.io/interview-preparation-notes/content/OOD/index.html
Open for extension but closed for modifications
The design and writing of the code should be done in a way that new functionality should be added with minimum changes in the existing code. The design should be done in a way to allow the adding of new functionality as new classes, keeping as much as possible existing code unchanged.
Example
class ShapeEditor{
    void drawShape(Shape s){
        if (s.m_type==1)
             drawRectangle(s);
         else if (s.m_type==2)
             drawCircle(s);
     };
    void drawRectangle(Shape s);
    void drawCircle(Shape s);
}
class Shape{}
class Rectangle extends Shape{}
class Circle extends Shape{}

//---> Every time if new shape added, we have to modify method in the editor class, which violates this rule!
// ---> change!!! write draw method in each shape concreted class
class Shape{ abstract void draw(); }
class Rectangle extends Shape{ public void draw() { /*draw the rectangle*/} }
class Circle extends Shape{ public void draw() { /*draw the circle*/} }
class ShapeEditor{
    void drawShape(Shape s){ s.draw(); }
    }

Dependency Inversion

The low level classes the classes which implement basic and primary operations(disk access, network protocols,...) and high level classes the classes which encapsulate complex logic(business flows, ...). The last ones rely on the low level classes.
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend on details. Details should depend on abstractions.
When this principle is applied it means the high level classes are not working directly with low level classes, they are using interfaces as an abstract layer.
Example
class WorkerWithTechOne{}
class Manager{
    WorkerWithTechOne worker;
}
// --> what if add other workers with other techniques?
// --> abstract worker!
interface Worker{}
class WorkerWithTechOne implements Worker{}
class WorkerWithTechTwo implements Worker{}
class Manager{
    Worker worker;
}

Interface Segregation

Clients should not be forced to depend upon interfaces that they don't use.
Instead of one fat interface, many small interfaces are preferred based on groups of methods, each one serving one submodule.
Example
interface work{
    public void work();
    // too much methods!
    public void life();
    public void rest();
}
// ---> change!!!
interface work{public void work();}
interface life{public void life();}
interface rest{public void rest();}

Single Responsibility

A class should have only one reason to change.
A simple and intuitive principle, but in practice it is sometimes hard to get it right.
This principle states that if we have 2 reasons to change for a class, we have to split the functionality in two classes. Each class will handle only one responsibility and on future if we need to make one change we are going to make it in the class which handle it. When we need to make a change in a class having more responsibilities the change might affect the other functionality of the classes.

Thursday, February 4, 2016

Law Of Demeter - Least Knowledge Principle



http://zhangyi.xyz/demeter-law-and-refactoring
https://www2.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/paper-boy/demeter.pdf
这个原则认为,任何一个对象或者方法,它应该只能调用下列对象:
  • 该对象本身
  • 作为参数传进来的对象(也可以是该对象的字段)
  • 在方法内创建的对象

这个原则用以指导正确的对象协作,分清楚哪些对象应该产生协作,哪些对象则对于该对象而言,又应该是无知的。如何理解这个原则?我们可以看看David Bock就该原则给出的一个绝佳案例。假设一个超市购物的场景,顾客(Customer)到收银台结账,收银员(Paper Boy)负责收钱
让我们将PaperBoy中charge()方法的代码翻译成这幕小话剧的对白。
“把钱包交出来!”收银员算出顾客要买的商品总价后,“温柔”地对顾客说道。
顾客言听计从,赶紧将钱包掏出来,恭恭敬敬地递给收银员。
接过钱包,收银员毫不客气地打开,检查里面的钱够不够。噢,不错,钱够了。收银员从钱包取出钱,心满意足地笑了。
判断一段代码是否违背了迪米特法则,有一个小窍门,就是看调用代码是否出现形如a.m1().m2().m3().m4()之类的代码。这种代码在Martin Fowler《重构》一书中,被名为“消息链条(Message Chain)”,有人更加夸张地名其为“火车残骸”。车祸现场啊,真是惨不忍睹。
那么,如下代码是否这样的残骸呢?
1
2
3
4
5
str.split("&")
 .stream()
 .map(str -> str.contains(elementName) ? str.replace(elementName + "=", "") : "")
 .filter(str -> !str.isEmpty())
 .reduce("", (a, b) -> a + "," + b);
不是的。这样的代码我们一般称之为“流畅接口或连贯接口(Fluent Interface)”。二者的区别在于观察形成链条的每个方法返回的是别的对象,还是对象自身。如果返回的是别的对象,就是消息链条。所谓m1().m2().m3().m4()的调用,其实是调用者不需要也不想知道的“知识”,把这些中间过程的细节暴露出来没有意义,调用者关心的是最终结果;而上述代码中的map()filter()等方法其实返回的还是Stream类。这一调用方式其初衷并非告知中间过程的细节,而是一种声明式的DSL表达,调用者可以自由地组合它们
http://blog.csdn.net/zhengzhb/article/details/7296930
定义:一个对象应该对其他对象保持最少的了解。
问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。
解决方案:尽量降低类与类之间的耦合。
         自从我们接触编程开始,就知道了软件编程的总的原则:低耦合,高内聚。无论是面向过程编程还是面向对象编程,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率。低耦合的优点不言而喻,但是怎么样编程才能做到低耦合呢?那正是迪米特法则要去完成的。
         迪米特法则又叫最少知道原则,最早是在1987年由美国Northeastern University的Ian Holland提出。通俗的来讲,就是一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。迪米特法则还有一个更简单的定义:只与直接的朋友通信。首先来解释一下什么是直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖、关联、组合、聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。
         举一个例子:有一个集团公司,下属单位有分公司和直属部门,现在要求打印出所有下属单位的员工ID。先来看一下违反迪米特法则的设计。
        现在这个设计的主要问题出在CompanyManager中,根据迪米特法则,只与直接的朋友发生通信,而SubEmployee类并不是CompanyManager类的直接朋友(以局部变量出现的耦合不属于直接朋友),从逻辑上讲总公司只与他的分公司耦合就行了,与分公司的员工并没有任何联系,这样设计显然是增加了不必要的耦合。按照迪米特法则,应该避免类中出现这样非直接朋友关系的耦合。修改后的代码如下:
class CompanyManager{
 public List<Employee> getAllEmployee(){
  List<Employee> list = new ArrayList<Employee>();
  for(int i=0; i<30; i++){
   Employee emp = new Employee();
   //为总公司人员按顺序分配一个ID
   emp.setId("总公司"+i);
   list.add(emp);
  }
  return list;
 }
 
 public void printAllEmployee(SubCompanyManager sub){
  sub.printEmployee();
  List<Employee> list2 = this.getAllEmployee();
  for(Employee e:list2){
   System.out.println(e.getId());
  }
 }
}
        修改后,为分公司增加了打印人员ID的方法,总公司直接调用来打印,从而避免了与分公司的员工发生耦合。
        迪米特法则的初衷是降低类之间的耦合,由于每个类都减少了不必要的依赖,因此的确可以降低耦合关系。但是凡事都有度,虽然可以避免与非直接的类通信,但是要通信,必然会通过一个“中介”来发生联系,例如本例中,总公司就是通过分公司这个“中介”来与分公司的员工发生联系的。过分的使用迪米特原则,会产生大量这样的中介和传递类,导致系统复杂度变大。所以在采用迪米特法则时要反复权衡,既做到结构清晰,又要高内聚低耦合。
迪米特法则:Law Of Demeter,LoD。
也被称为最少知识原则,Least Knowledge Principle,LKP。
就是说一个对象应该对其他对象保持最少的了解。正如最少知识原则这个定义一样,一个类应该对其耦合的其他类或所调用的类知道得最少。所耦合的类内部无论如何复杂,怎么实现的我都不需要知道,我只调用你public出来的这些方法,其他都不用知道。
看到这里很多人都会明白,这种场景在实际开发中是非常常见的一种情况。对象A需要调用对象B的方法,对象B有需要调用对象C的方法……就是常见的getXXX().getXXX().getXXX()……类似于这种代码。如果你发现你的代码中也有这样的代码,那就考虑下是不是违反迪米特法则,是不是要重构一下了。
  • 类A只与最直接的朋友类B通信,不与类C通信;
  • 类A只调用类B提供的方法即可,不用关心类B内部是如何实现的(至于B是怎么调用的C,这些A都不用关心)。
迪米特法则的目的是让类之间解耦,降低耦合度。只有这样,类的可复用性才能提高。
但是迪米特法则也有弊端,它会产生大量的中转类或跳转类,导致系统的复杂度提高。
所以我们不要太死板的遵守这个迪米特法则,在系统设计的时候,在弱耦合和结构清晰之间反复权衡。尽量保证系统结构清晰,又能做到低耦合。
The Law of Demeter (LoD) or principle of least knowledge is a specific case of loose coupling.
  • Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.
  • Each unit should only talk to its friends; don't talk to strangers.
  • Only talk to your immediate friends.
The fundamental notion is that a given object should assume as little as possible about the structure or properties of anything else (including its subcomponents), in accordance with the principle of "information hiding".
a module should not know about the inner details of the objects it manipulates. If a code depends upon internal details of a particular object, there is good chance that it will break as soon as internal of that object changes. 

One mistake many Java programmer makes it exposing internal detail of object using getter methods and this is where principle of least knowledge alerts you.

In short, the Law of Demeter aims to keep you from doing things like this:
objectA.getObjectB().getObjectC().doSomething(); ===> contrvsery

When you write code like this, not only are you exposing yourself to changes in the ObjectA class, you're also exposing yourself to changes that may occur in ObjectB and ObjectC as well.
Forces
  • Your classes will be "loosely coupled"; your dependencies are reduced.
  • Reusing your classes will be easier.
  • Your classes are less subject to changes in other classes.
  • Your code will be easier to test.
  • Classes designed this way have been proven to have fewer errors.
Exception 1: Data Structures
Exception 2: The Builder Pattern and Other Fluent APIs

When an API is designed to be fluent (and therefore, usually chained), there’s no good reason to lose the readability just to be a strict Law of Demeter follower. For example, java 8’s Stream API would be worthless if you didn’t allow yourself to chain methods.
http://www.dan-manges.com/blog/37
Models should define business logic and be able to stand alone from views.
http://c2.com/cgi/wiki?LawOfDemeter

Practice
https://medium.com/@orhanobut/yet-again-law-of-demeter-4a7e8fa7707d
  private void showAvatar(){
    Image image = user.getAccount().getImage();
  }
==>
public class User { ...
public Image getAvatar(){
if (account == null) {
return;
}
account.getImage();
}
}
public class Foobar {
public void showAvatar() {
Image image = user.getAvatar();
}
}
http://blog.csdn.net/vking_wang/article/details/8455636
又称最少知识原则(Least Knowledge Principle),一个对象应该对其他对象有最少的了解
一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。

        类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。
        迪米特法则包含4层含义:
        1)只和朋友交流
        Only talk to your immediate friends.两个对象之间的耦合就成为朋友关系。即,出现在成员变量、方法输入输出参数中的类就是朋友;局部变量不属于朋友。
--> 不与无关的对象发生耦合!
        方针:不要调用从另一个方法中返回的对象中的方法!只应该调用以下方法:
  • 该对象本身的方法
  • 该对象中的任何组件的方法
  • 方法参数中传入的对象的方法
  • 方法内部实例化的对象的方法
        例如:Teacher类可以命令TeamLeader对Students进行清点,则Teacher无需和Students耦合,只需和TeamLeader耦合即可。
反例:
public float getTemp(){
     Thermometer t = station.getThermometer();
     return t.getTemp();
}
客户端不应该了解气象站类中的温度计对象;应在气象站类中直接加入获取温度的方法。改为:
public float getTemp(){
     return station.getTemp();
}


        2)朋友间也应该有距离
        即使是朋友类之间也不能无话不说,无所不知。
--> 一个类公开的public属性或方法应该尽可能少!
        3)是自己的就是自己的
        如果一个方法放在本类中也可以、放在其他类中也可以,怎么办?
--> 如果一个方法放在本类中,既不增加类间关系,也对本类不产生负面影响,就放置在本类中。
        4)谨慎使用Serializable
        否则,若后来修改了属性,序列化时会抛异常NotSerializableException。
建议:
        迪米特法则的核心观念是:类间解耦。
        其结果是产生了大量中转或跳转类。

Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts