Magento2: what is the basic difference between plugin and preference?

A preference is equivalent to class rewriting from Magento 1. It's equivalent to saying, "Whenever code asks for ClassA, give them MyClassB instead." MyClassB is expected to be a complete implementation of ClassA, plus whatever behavior you add or modify on top.

As in Magento 1, only one preference (rewrite) can be active for a class at one time unless you chain them manually (such that MyClassB extends OtherClassB, and OtherClassB extends ClassA).

A plugin allows you to execute code before, around, or after methods from the class you're hooking onto. Your plugin class does not replace the target class, and it is not an instance of it. You just have methods before{method}, around{method}, after{method} which get executed at the appropriate time in respect to {method} on the target class.

Since plugins do not replace the target class, any number of plugins can be active on a class simultaneously. Magento just executes them one after another based on the sortOrder parameter in your XML.

Because of that, plugins are much more flexible than preferences. You should use plugins whenever possible, and avoid preferences for rewriting classes unless absolutely necessary.

You can read more about how plugins work and how to use them in the official documentation.


In simple words

Preference is used for overriding class

Plugin is used for adding functionality before, after and around methods.

For As Your example:

<preference for="Magento\Catalog\Block\Product\ListProduct" type="Vendor\MyModule\Block\Product\ListProduct" /> 

Whenever code ask for ListProduct, preference said that

Hey, use Vendor\MyModule\Block\Product\ListProduct instead of Magento\Catalog\Block\Product\ListProduct

<type name="Magento\Catalog\Model\Product">
<plugin name="magento-catalog-product-plugin" type="Training\Test\Model\Product" sortOrder="10"/>
</type>

Whenever code ask for getPrice(), plugin said that

Hey use my getPrice() method before, after and around your getPrice() method